一、对象的创建和销毁过程
1、对象的创建
a、给对象划分内存空间(栈、堆)
b、执行初始化列表
根据继承表的顺序调用父类的构造函数,可以调用无参构造,也可以调用有参构造 方式 构造函数 : 父类名(参数)
根据成员的定义顺序调用类类型成员的构造函数,可以调用无参构造,也可以调用有参构造 方式 构造函数 : 成员名(参数)
初始化其他成员
c、执行自己的构造函数、申请其他资源
2、对象的销毁
a、执行自己的析构函数、释放资源
b、根据成员的定义顺序的逆序地调用类类型成员的析构函数
c、根据继承表的顺序,逆序地调用父类的析构函数
d、释放对象的内存
二、成员函数是如何分辨调用它的对象
1、对象的内存只存储它的成员变量,但是不存储成员函数指针
2、当通过对象调用成员函数时,编译器会自动把对象的地址传递给它的成员函数,也就是成员函数会有隐藏的参数,这个参数存储对象的地址,也就是this指针
3、this虽然是隐藏的,但是当需要时也可以显式调用
三、常函数
1、被const修饰过的成员函数,叫常函数
2、已知当通过对象调用成员函数时,编译器会把对象的地址隐式地传递给成员函数
3、如果对象被const修饰,则不能再调用普通的成员函数了,编译器会报错,因为此时传递的对象地址也是带有const属性的,而普通成员函数的隐式的this指针是不带const属性,也就是把带有const属性的指针赋值给不带const属性的指针变量,有安全隐患,编译器不允许
4、如果成员函数被const修饰,其实就是修饰的this指针,这样成员函数的this指针就具备const属性,这样就可以被同样具有const属性的对象调用了
5、const属性的对象只能调用常函数,常函数也只能调用常函数
6、在常函数中是不能修改变量的值,要么强转去常属性,要么用mutable修饰要修改的成员变量
面试问题:
1、C语言中const与C++中的const有什么不同?
C语言和C++的const都是用来保护数据不被显式修改
不同:
a、C++会优化const变量的取值过程,哪怕const变量的内存被强行修改,但是也不会改变变量在编译器中的值,这种机制更安全
b、C++中const还可以用来修饰成员函数(给隐藏的this指针增加const属性),定义常函数
2、一个空的结构体,在C语言中和C++分别占多少字节?为什么?
C语言中占0字节,而C++中占1字节
在C++中结构体是可以定义成员函数的,而且有默认的四个成员函数(构造、析构、拷贝构造、赋值),当通过构造对象调用成员函数时,会把对象的地址自动传递给成员函数,这种机制就要求该对象必须在内存中占有一席之地,因此就算结构没有任何成员,编译器也会让结构最起码有1字节
四、拷贝构造与赋值操作
拷贝构造也是一种特殊的构造函数,格式为:
类名(const 类名& that)// const可加可不加,但是加更好
{
}
什么时候调用拷贝构造:
当使用旧的对象给新对象初始化时,就会自动调用拷贝构造
Test t1; // 调用无参构造
Test t2 = t1; // 调用拷贝构造
拷贝构造的任务:
顾名思义拷贝构造负责把旧对象中的成员变量拷贝给新对象,而且编译器默认生成 的具有该功能的拷贝构造函数
什么时候需要显式地实现拷贝构造函数:
普通情况下编译器自动生成的拷贝构造完全够用,但是当类中的成员有指针且为指针分配了堆内存时,默认的拷贝构造只会对指针变量的值进行拷贝,
这样导致两个对象的指针成员指向同一块同一块堆内存,在执行析构函数时,就会造成重复释放堆内存导致内存崩溃,这种情况下就应该显式地实现拷贝构造函数。
深拷贝与浅拷贝:
当类中的成员有指针且为指针分配堆内存,浅拷贝(默认的拷贝构造)只拷贝指针变量的值,深拷贝(显式实现拷贝构造)不拷贝指针变量的值,而拷贝指针变量所指向的内存中的内容到新内存中。
赋值操作:
所谓的赋值操作,就是把一个对象给另一个对象赋值(两个对象都已经创建完毕),在C++中会把运算符当作函数,使用运算符时会调用运算符函数
类名& operator=(const 类名& that)
{
...
return *this;
}
Test t1,t2; // 无参构造
t1 = t2; // 赋值操作
赋值操作的任务:
它与拷贝构造的任务基本一致,同样的编译器也会自动生成一个具有浅拷贝功能的赋值运算符函数,当需要进行深拷贝时不仅需要显式地实现拷贝构造,同样需要显式地实现赋值运算符函数
显式地实现赋值操作需要注意的问题:
虽然赋值运算符函数和拷贝构造函数的任务一样,但是环境不同
问题1:两个对象的指针都已经分配了堆内存
a、先释放被赋值者的指针变量所指向的内存
b、再给被赋值者重新分配指针变量所需要的内存
c、把赋值者的指针变量所指向内存的内容深拷贝给被赋值者的指针变量所指向的内存
问题2:可能出现对象自己给自己赋值
判断this指针和赋值者的地址是否相同,如果相同则立即结束
问题3:赋值运算符可能会出现连续赋值
赋值运算符函数的返回值改为类类型的引用
n1 = n2 = n3;