一:拷贝构造,深浅拷贝
class A{
public:
int i;
A(const A& tmpa){
i = tmpa.i;
cout << "拷贝构造函数被调用" <<endl;
}
A(){
i = 0;
cout << "构造函数被调用" <<endl;
}
~A(){
cout << "析构函数被调用" <<endl;
}
A(int value):i(value){ // 类型转换构造函数
cout << "A(value) 构造函数被调用" <<endl;
}
}
int main(){
A a10(1000); // 类型转换构造函数被调用
A a11 = 1000; // 类型转换构造函数被调用
A a12 = A(1000); // 同上
A a13 = (A)(1000); // 同上
/*
A(value) 构造函数被调用
A(value) 构造函数被调用
A(value) 构造函数被调用
A(value) 构造函数被调用
析构函数被调用
析构函数被调用
析构函数被调用
析构函数被调用
*/
}
/*
在vs2019的编译器中 对以上的代码进行了优化 在Linux的g++编译器输出如下:
A(value) 构造函数被调用
A(value) 构造函数被调用
拷贝构造函数被调用
析构函数被调用
A(value) 构造函数被调用
拷贝构造函数被调用
析构函数被调用
A(value) 构造函数被调用
拷贝构造函数被调用
析构函数被调用
析构函数被调用
析构函数被调用
析构函数被调用
析构函数被调用
*/
// 后三个调用的类型转换构造函数都会生成一个临时对象
A a10
// 这个代码在编译器中:
//A a10; // 只定义对象不调用构造函数
//a10.A::A(1000);
A a11 = 1000;
A a12 = A(1000);
A a13 = (A)(1000);
// 这三行代码在编译器中;
// A _a0 // 先定义一个临时对象
// _a0.A::A(1000);
// A a11;
// a11.A::A(_a0); // 拷贝构造函数被调用
// _a0.A::~A();
A a11 = 1000;
/*
和后两行还是有一定的差别,先将1000转换成A对象(调用类型转换构造函数
// explicit 拒绝隐式类型转换。
*/
// 以上这些情况具体还是要看编译器时如何操作,具体是优化掉了类型转换构造函数还是没有优化
二 :拷贝构造函数是否必须有? (视情况而定
1.如果你只有一些简单的成员变量类型, int double ,这种情况不需要拷贝构造函数
编译器本身就支持成员变量的的copy。(bitwise copy 按位拷贝 (浅拷贝
class A{
public:
int i;
// A(const A& tmpa){
// i = tmpa.i;
// cout << "拷贝构造函数被调用" <<endl;
// }
A(){
i = 0;
cout << "构造函数被调用" <<endl;
}
~A(){
cout << "析构函数被调用" <<endl;
}
A(int value):i(value){ // 类型转换构造函数
cout << "A(value) 构造函数被调用" <<endl;
}
}
int main(){
A mya;
mya.i = 150;
A mya2(mya); // 编译器本身支持bitwise 拷贝
cout << mya2.i <<endl;
/*
构造函数被调用
150
析构函数被调用
析构函数被调用
*/
}
// 这里 如果说写了自己的拷贝构造函数,那么就是告诉编译器不要执行bitwise copy
// 程序员本身来负责各个值的初始化
2.当需要处理复杂的成员变量类型的时候需要些拷贝构造函数
class A{
public:
int i;
int *pm;
// A(const A& tmpa){
// i = tmpa.i;
// cout << "拷贝构造函数被调用" <<endl;
// }
A(){
i = 0;
pm = new int(100);
cout << "构造函数被调用" <<endl;
}
~A(){
delete pm;
cout << "析构函数被调用" <<endl;
}
A(int value):i(value){ // 类型转换构造函数
pm = new int(100);
cout << "A(value) 构造函数被调用" <<endl;
}
}
int main(){
A mya;
mya.i = 150;
A mya2(mya);
cout << mya2.i <<endl;
}
// 这里假设使用的是按位copy 那么mya2里面的指针也是指向mya的new开辟的地址
// 这时mya被析构掉,那么mya2的指针非法。所以这时候就需要写一个拷贝构造函数
3. 复杂的数据类型的拷贝构造函数
class A{
public:
int i;
int *pm;
A(const A& tmpa){
pm = new int(100);
memcpy(pm, tmpa.pm, sizeof(int));
// 这里使用的是深拷贝 彻底将对象的内容拷贝过来
// 浅拷贝还是操作的同一个内存地址
i = tmpa.i;
cout << "拷贝构造函数被调用" <<endl;
}
A(){
i = 0;
pm = new int(100);
cout << "构造函数被调用" <<endl;
}
~A(){
delete pm;
cout << "析构函数被调用" <<endl;
}
A(int value):i(value){ // 类型转换构造函数
pm = new int(100);
cout << "A(value) 构造函数被调用" <<endl;
}
}
int main(){
A mya;
mya.i = 150;
A mya2(mya);
cout << mya2.i <<endl;
}