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