C++类和对象 后篇
构造函数的初始化列表🤔
由于某些成员必须在定义时初始化(引用,const,自定义类型),所以在默认构造函数处有初始化列表来解决问题。
不管我们写不写初始化列表,每个成员都会经过它。并且缺省值给的是初始化列表,初始化列表初始化的顺序与声明顺序一致。初始化列表在默认构造函数处,以冒号开始,逗号分割,括号内为参数,这是C++规范准则,无法更改。
每个成员变量在初始化列表中仅经过一次,与函数体内的初始化有区别,函数体内的初始化更应该称为赋值。以下面代码为例:
class Date { public: Date(int year, int month, int day, int& i) :_year(year), //day也会经过初始化列表,但是内置类型编译器不处理,所以是随机值 _month(month), _x(10), ref(i), _a(100) //如果不写也会处理,自定义类型会去调默认构造 { _day = day; } private: int _year; int _month; int _day; const int _x; int& ref; A _a; //自定义类型 };
隐式类型转换🤔
C++支持单参数构造函数的隐式类型转换,如下代码:
class A { public: A(int a) :_a(a) { cout << _a << endl; } A(const A& a) :_a(a._a) { cout << "a" << endl; } ~A() { } private: int _a; };
隐式类型转换会在两个类型间建立一个临时变量,然后才进行转换,不过在某些场景新版编译器会进行优化,使其跳过拷贝构造。如下图:
并且,C++11支持多参数的隐式类型转换:
如果不想要隐式类型发生,只需要在构造函数前面加explicit就行:
匿名对象🤔
对象分为两种类型,一种为匿名对象,一种为有名对象,有名对象的生命周期在当前局部域,匿名对象的生命周期仅在这一行。匿名对象具有常性。
匿名对象一般用于确定只使用一次时,可以简化代码
使用const修饰匿名对象可以延长生命周期。下图匿名对象会在ref出了作用域才会销毁。
static成员函数🤔
在类创建了static成员,那么就变成了对象公有成员(存在静态区中),static不走初始化列表,所以不能给缺省值,需要在类中声明,类外定义。
如果创建了一个静态成员函数,那么它没有this指针,可以直接用类域调用,并且静态成员函数不能访问非静态成员。
友元🤔
友元分为友元函数和友元类,它能放在类中的任何位置,其代码为:
friend 函数声明; //如friend void Print(); 声明Print函数为友元函数 friend class 类名; //friend class B; 声明B为友元类 注:只能单方面友元
友元有以下特性:
- 友元函数可访问类的私有和保护成员,但不是类的成员函数
- 不能用const修饰
- 不受访问限定符限制
- 一个函数可以是多个类的友元
- 友元函数的调用与普通函数的调用原理相同
内部类🤔
在类中再创建一个类,不过它俩还是独立的两个类,内存大小都为4字节,调用方法(public限定符下)为C:😄 dd,并且内部类是外部类的友元,该题专门说明了static和内部类的用法,感兴趣可以看看。
拓展知识🤔
每个编译器优化不同,编译器优化不属于C++标准规定。当构造函数和拷贝函数在同一步骤时,编译器会进行优化,使构造和拷贝合二为一。
这里本该是拷贝构造两次,一次是aa拷贝给临时对象,临时对象再拷贝给ret,编译器优化以后aa直接拷贝给ret(也需要在同一步骤中)
这里由于返回值会创建临时变量造成拷贝,所以也优化了
结尾👍
以上便是本篇博客全部内容,如果有疑问或者建议都可以私信笔者交流,大家互相学习,互相进步!🌹