调用顺序
如果一个类里面存在其他类的属性对象,那么构造函数和析构函数的调用顺序为:
创建时:先调用属性对象的构造函数,在执行自己的构造函数;
销毁时:先调用自己的析构函数,再执行属性对象的析构函数;
构造函数
构造函数在对象被销毁时调用;
1 | class Student{ |
析构函数
析构函数在对象被销毁时调用;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37class Student{
private:
char* name;
int age;
public:
// 无参构造函数(会覆盖父类的无参构造函数)
Student(){
cout << "调用无参构造函数" << endl;
this->name = (char*)malloc(sizeof(char)*100);
strcpy(name, "json");
}
// 定义有参的构造函数后,默认无参构造函数将被覆盖
Student(int age, char* name){
// 字符串后面会带有0作为结束符,所以要加1
int len = strlen(name);
this->name = (char*)malloc(len + 1);
strcpy(this->name, name);
this->age = age;
}
// 对象被销毁时调用,可以做善后处理,比如,释放内存
~Student(){
cout << "调用析构函数" << endl;
free(name);
}
};
void func(){
Student t;
}
void main(){
//func();
system("pause");
}
拷贝构造函数
调用场景:
1,变量间的赋值: T t1 = t2;
2,函数调用时传参,值传递时调用;
3,作为函数返回值返回,给其他变量赋值时(与第1种情况同 )
1 | class Student{ |
浅拷贝问题
默认情况下,拷贝构造函数是浅拷贝,也就是值拷贝。当我们在构造函数中为成员变量开辟了动态
堆内存空间,进行浅拷贝后,拷贝变量也会指向同一个堆内存空间,此时,在变量销毁时,调用
析构函数,源变量和拷贝变量都会对同一内存空间进行释放,此时就会报错。
(浅拷贝是值拷贝,而指针的值是地址,所以拷贝出来都是指向同一个地址空间)1
2
3
4
5
6
7
8void copyPro(){
Student stu(10, "llll");
// stu2拷贝了stu的变量值,其成员变量name同时指向了同一个内存空间
Student stu2 = stu;
// 函数销毁时,stu和stu2都会调用析构函数去释放内存空间,导致重复释放的问题
}
深拷贝解决浅拷贝问题:
开辟一段新的内存,不只拷贝变量值,还会拷贝对应的地址内容;1
2
3
4
5
6
7Student(const Student &obj){
int len = strlen(obj.name);
// 字符串后面会带有0作为结束符,所以要加1
this->name = (char*)malloc(len + 1);
strcpy(this->name, obj.name);
this->age = obj.age;
}