C++ 类和对象下

本文详细探讨了C++中的构造函数、初始化列表、隐式类型转换、静态成员、友元功能以及匿名对象的特性,同时介绍了编译器如何进行传参和返回值优化以提高效率。
摘要由CSDN通过智能技术生成

目录

1.再谈构造函数

2.初始化列表

2.1定义

2.2分析代码 

3.隐式类型转换

3.1单参数(C++98)

3.2双参数(C++11)

3.3explicit关键字

4.Static成员

4.1特性

5.友元

5.1友元函数

5.2友元类

6.内部类(很少用)

7.匿名对象

7.1特性

8.编译器的优化

8.1传参优化

8.2返回优化


1.再谈构造函数

class C
{
public:
	C(int grade)//这个不是默认构造
		:_grade(grade)
	{}
private:
	int _grade;
};

class A
{
public:
	A(int grade)
		:_grade(grade)
		, _a(3)
		, _b(_grade)
		, _c(99)
	{
		cout << "A(int grade)" << endl;
	}
	A(const A& x)//这个const注意
		:_grade(x._grade)
		, _a(x._a)
		, _b(x._b)
		, _c(x._c)
	{
		cout << "A(const A& x)" << endl;
	}
private:
	int _grade;
	const int _a;
	int& _b = _grade;
	//C _c(10);
	C _c = 10;
};

int main()
{
	A a(10);
	return 0;
}

2.初始化列表

为了解决:const引用类型没有默认构造可以用,自定义类型可能会没有默认构造可以用

2.1定义

①初始化列表是成员变量定义的地方,在构造函数(拷贝构造也是构造)中使用,所有的成员都会走初始化列表

②定义顺序为成员变量的声明顺序

③在初始化列表的成员就在初始化列表里定义,没有的再定义成缺省值

④初始化列表只能出现一次成员,不然会报错

其实说来说去还是对这句话的理解:

如果这个成员没有在初始化列表:内置类型不做处理(除非给了缺省值),对自定义类型调用它的默认构造

2.2分析代码 

C类是没有写默认构造

错误①

我刚开始出现这个问题,这个C类要在A类上面定义

错误②

C  _c(10),会有语法错误,C  _c; 这样也不行,因为C类没有默认构造,什么事默认构造:类和对象上是引入了初始化列表的一个原因,因为没法初始化没有默认构造的自定义类型

3.隐式类型转换

3.1单参数(C++98)

对于C  _c = 10;  来说,这里有个隐式类型的转换,对于单个参数的构造函数,支持隐式类型转换

int main()
{
	A a1(10);             //1
	A a2 = 2;			  //2
	A& a3 = 10;			  //3
	const A& a4 = 10;     //4

	return 0;
}

①单参数的构造函数

②先构造函数初始化临时对象,在执行拷贝构造   优化为构造

③临时对象具有常性,编译错误

④const具有常性,这里引用了临时对象,所以编译器没法优化(新一点的编译器会优化掉)

3.2双参数(C++11)

没有区别,两个参数用{},大括号括起来就行;例:A a = { 2, 2 };

3.3explicit关键字

explicit A(int grade)

 在构造函数的前面加上explicit就行,这样就会禁止隐式类型的转换

4.Static成员

比如说我们要统计创建对象的次数

class A
{
public:
    A(int grade)
        ://...
	{
		//...
        count++;
	}

private:
	int _grade;
	const int _a;
	int& _b = _grade;
	C _c = 10;
	static int count;
};

int A::count = 0;//类外定义,可以不初始化

我就把关键部分写下,这样会出现一个问题,我们必须要有对象才能知道创建过的对象的个数。

例子如下

void func()
{
    A a[10];
}


int main()
{
    func();
    A a;
    cout<< a.count - 1<<endl;
    return 0;
}

我们还要在类内加一个默认构造,直接用全缺省的默认构造 :A(int grade = 0)

其实很麻烦①在类内加一个GetCount()的函数,为了知道个数②还有在定义一个对象③GetCount还要减一

所以引入新的办法:静态函数

样例如下

通过或者对象直接读取count(private修饰的话,不能读取)所以通过静态成员函数

class A
{
public:
	static int GetCount()
	{
		return count;
	}
private:
	static int count;
};
int A::count = 0;

int main()
{
	A::GetCount;

	A a;
	a.GetCount();
}

4.1特性

①静态成员函数就是为了静态成员变量而生的

②静态成员函数不能访问(读写)非静态成员变量(因为没有隐藏的this指针)

③静态成员属于所有的对象,属于整个类

④同样有访问权限,不能被const修饰

5.友元

增加耦合度,破坏封装,不建议多用

5.1友元函数

在类内声明后,友元函数可以直接访问类的私有成员
 

class A
{
	friend void func();
public:
private:
}
void func()
{
	A a;
	cout << a._grade;
}

①友元声明可以放在类里面的任何地方

②友元函数不能用const修饰

③友元声明可以放在多个类里

5.2友元类

class A
{
	friend class B;
public:
private:
	int _grade;
};

class B
{
public:
	int func(A a)
	{
		return a._grade;
	}
private:

};

①友元关系是单项的

②友元关系不能传递

总结:你看  类A 里面有个B ,就好比A给了B一把钥匙,那么B就可以访问它,而B,没有给A,就是这么合理

6.内部类(很少用)

class A
{
public:
	class B
	{
	public:
		int func(A a)
		{
			count++;
			a._grade++;
			return a._grade;
            //_grade++;  ×
		}
	private:

	};
private:
	int _grade;
	static int count;
    //...
};
int A::count = 0;

①内部类受访问限定符的限制

②非静态成员必须与特定的对象相对,(用对象,例: a._grade++,   直接_grade找不到)

③sizeof的大小是外部类,和内部类无关

总结:内部类是外部类的友元,内部类由外部类的钥匙

7.匿名对象

7.1特性

class A
{
public:
	static int GetCount()
	{
		return count;
	}
	void func()
    {

    }
private:
	int _grade;
	const int _a;
	int& _b = _grade;
	C _c = 10;
	static int count;

};
int A::count = 0;

int main()
{
    A().func();
	A().GetCount();
}

①生命周期只在这一行

②如果func是private,不能访问

③创建匿名对象,会去调用拷贝构造

④匿名对象具有常性

8.编译器的优化

8.1传参优化

void func1(A a)
{
}
void func2(A& a)
{
}
void func3(const A& a)
{
}

int main()
{
	A a = 1;         //1	构造+拷贝->构造

	func1(a);        //2	拷贝
	func1(1);        //3	构造+拷贝->构造
	func1(A());      //4	构造+拷贝->构造

	func2(a);        //5	直接传
	func2(1);        //6	临时对象具有常性,也就是临时对象不能改变,计算const修饰
	func2(A());      //7	同6

	func3(a);        //8	直接传
	func3(1);        //9    构造+拷贝
	func3(A());      //10   构造+拷贝
	return 0;
}

 9和10不能优化,这个临时对象必须有,不然怎么引用

总结:接收返回值,尽量拷贝构造接收,不要赋值接收

8.2返回优化

A func1()
{
	A a;
	return a;
}

A func2()
{
	return A();
}
int main()
{
	func1();//构造+拷贝(拷贝给临时对象)
	A a1 = func1();//构造+拷贝+拷贝->构造+拷贝

	func2();//构造+拷贝->构造//你这么想他构造出来的是临时对象,拷贝构造出来的也是临时对象
	A a2 = func2();//构造+拷贝+拷贝->构造
}

总结:函数返回对象时,尽量返回匿名对象

注:新的编译器调试不出效果,它优化的厉害

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值