1.拷贝构造函数调用时机
C++中拷贝构造函数调用时通常有三种情况
-
使用一个已经创建完毕的对象来初始化一个新对象
Person p3=p2; //调用拷贝析构函数1次,析构函数一次 ,未定义拷贝构造函数,就直接复用上次构造函数,只执行一次析构函数
#include<iostream>
using namespace std;
class Person
{
public:
int m_age;
Person()
{
cout << "构造函数调用" << endl;
}
Person(int a)
{
m_age = a;
cout << "有参构造函数调用" << endl;
}
Person(const Person &p )
{
m_age = p.m_age;
cout << "person拷贝构造函数调用" << endl;
}
~Person()
{
cout << "析构函数函数调用" << endl;
}
};
void test01()
{
Person p1{ 10 };//调用有参析构函数1次,析构函数一次
Person p2{ 20 };//调用有参析构函数1次,析构函数一次
Person p3=p2; //调用拷贝析构函数1次,析构函数一次 ,未定义拷贝构造函数,就直接复用上次构造函数,只执行一次析构函数
cout << "P2的年龄:" << p2.m_age << endl;
}
int main()
{
test01();
return 0;
}
-
值传递的方式给函数参数传值
void test02(Person a)
{}
Person p3;
test02(p3);
结果:
构造函数调用
person拷贝构造函数调用
析构函数函数调用
析构函数函数调用
-
以值方式返回局部对象
Person test02()
{
Person p1;
cout << (int*)&p1<<endl; //(int*)&p 表示将地址强制转换成指向int 类型数据的指针
return p1;
}
test02();
结果:
构造函数调用
00D6F60C
person拷贝构造函数调用
析构函数函数调用
析构函数函数调用
2.构造函数调用规则
默认情况下,C++编译器至少给一个类添加3个函数
-
默认构造函数(无参,函数体为空)
-
默认析构函数(无参,函数体为空)
-
默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则:
-
如果用户定义有参构造函数,C++不再提供默认无参构造函数,但是会提供默认拷贝构造
-
如果用户定义拷贝构造函数,C++不会再提供其他构造函数
3.深拷贝与浅拷贝
深浅拷贝是面试经典问题,也是一个终点
浅拷贝:简单的赋值拷贝操作
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
#include<iostream>
using namespace std;
class Person
{
public:
int m_age;
int *m_height;
Person()
{
cout << "默认构造函数调用" << endl;
}
Person(int a,int height) //此时同此引用,就是浅拷贝
{
m_age = a;
m_height = new int(height);
cout << "有参构造函数调用" << endl;
}
//Person(const Person &p )
//{
// m_age = p.m_age;
// m_height = new int(*p.m_Height);
// cout << "person拷贝构造函数调用" << endl;
//}
~Person()
{
cout << "析构函数函数调用" << endl;
if(m_height!=NULL)
{
delete m_height;
m_height= NULL;
}
}
};
int main()
{
Person p1(10, 120);
Person p2=p1;
return 0;
}
结果:
程序崩溃
执行结果:调用一次构造函数,调用两次析构函数,两个对象的指针成员所指内存相同,这会导致什么问题呢?name指针被分配一次内存,但是程序结束时该内存却被释放了两次,会导致崩溃!
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
深拷贝:在堆区重新申请空间,进行拷贝操作
#include<iostream>
using namespace std;
class Person
{
public:
int m_age;
int *m_height;
Person()
{
cout << "默认构造函数调用" << endl;
}
Person(int a,int height) //此时同此引用,就是浅拷贝
{
m_age = a;
m_height = new int(height);
cout << "有参构造函数调用" << endl;
}
Person(const Person &p )
{
m_age = p.m_age;
m_height = new int(*p.m_height);
cout << "person拷贝构造函数调用" << endl;
}
~Person()
{
cout << "析构函数函数调用" << endl;
if(m_height!=NULL)
{
delete m_height;
m_height= NULL;
}
}
};
int main()
{
Person p1(10, 120);
Person p2=p1;
return 0;
}
结果:
有参构造函数调用
person拷贝构造函数调用
析构函数函数调用
析构函数函数调用
注意:
-
浅拷贝的问题是:堆区的内存重复释放
-
析构函数中的代码可以释放堆区中开辟的数据
总结:如果属性在堆区开辟,一定要自己提供拷贝构造函数,否者会出现浅拷贝问题