wordpress一个主站多个子站,男女做羞羞的故事网站,手机如何制作图片,青岛网络推广服务拷贝构造函数和赋值函数
什么是拷贝构造
是一种特殊构造函数#xff0c;如果没有显式的实现#xff0c;编译器就会自动生成。
class 类名
{
public:// 拷贝构造类名(const 类名 that){}
};
什么时候会调用拷贝构造
当使用一个类对象给另一个新的类对象初始化时如果没有显式的实现编译器就会自动生成。
class 类名
{
public:// 拷贝构造类名(const 类名 that){}
};
什么时候会调用拷贝构造
当使用一个类对象给另一个新的类对象初始化时就会自动调用拷贝构造。
#include iostream
using namespace std;
class Test
{
public:Test(void){ cout 调用了普通的构造函数 endl;} Test(const Test that){ cout 调用了拷贝构造 endl;}
};
void func(Test t)
{
}
int main(int argc,const char* argv[])
{Test t1; // 调用的是普通构造Test t2 t1; // 调用的是拷贝构造func(t1); // 调用的是拷贝构造return 0;
}
拷贝构造的任务是什么
拷贝构造参数对象的所有成员变量挨个赋值给新对象的成员变量一般情况下编译器自动生成的拷贝构造就能完全满足我们使用需求。
什么时候需要显式实现拷贝构造
当成员变量中有指针成员且指向了堆内存就需要显式实现拷贝构造。
编译器自动生成的拷贝构造只会对成员变量挨个赋值如果成员变量中有指针变量且指向堆内存结果就两个对象的指针变量同时指向一份堆内存当它们执行析构函数时会把这块堆内存释放两次产生 double free or corruption 的错误。
正确的做法应该是先给新对象的指针变量重新申请一份堆内存然后把旧对象的指针变量所指向的内存拷贝到新对象的指针变量所指向的内存。
#include iostream
using namespace std;
class Test
{int* ptr;
public:Test(int num){ptr new int;cout new: ptr endl;*ptr num;}
~Test(void){cout delete: ptr endl;delete ptr;}
/* 编译器生成的拷贝构造会造成 double freeTest(const Test that){ptr that.ptr; }*/Test(const Test that){// 给新对象的指针变量重新申请堆内存ptr new int(*that.ptr);// 把旧对象的指针变量所指向的内存拷贝给新对象的指针变量所指向的内存如果不方便解引用时可以使用memcpy函数}
void show(void){cout val: *ptr addr: ptr endl;}
};
int main(int argc,const char* argv[])
{Test t1(12345);Test t2 t1;t1.show();t2.show();
return 0;
}
什么是赋值函数
是一种特殊的成员函数如果没有显式实现编译器会自动生成。
class 类名
{
public:// 赋值函数const 类名 operator(const 类名 that){}
};
什么时候会调用赋值函数
当一个旧对象给另一个旧对象赋值时会自动调用赋值函数。
当一个旧对象给另一个新对象初始化时会自动调用拷贝构造函数。
#include iostream
using namespace std;
class Test
{
public:Test(const Test that){ cout 调用了拷贝构造 endl;}
void operator(const Test that){ cout 调用了赋值函数 endl;}
};
int main(int argc,const char* argv[])
{Test t1; // 调用了普通的构造函数Test t2 t1; // 调用了拷贝构造t1 t2; // 调用的是赋值函数return 0;
}
赋值函数的任务是什么
赋值函数与拷贝构造的任务几乎相同都是挨个给成员变量赋值但如果需要显式实现时它的业务逻辑不同。
什么时候需要显式实现赋值函数
当需要显式实现拷贝构造时就需要显式实现赋值函数它们两个面临问题是一样的。
赋值函数不应该对成员指针变量赋值而应该对象成员指针变量所指向的内存进行拷贝。
#include iostream
using namespace std;
class Test
{int* ptr;
public:Test(int num){ptr new int;cout new ptr endl;*ptr num;}~Test(void){cout delete ptr endl;// delete ptr;}
Test(const Test that){ptr new int;// 如果不方便解引用可以调用memcpy函数进行拷贝*ptr *that.ptr;cout new ptr 调用了拷贝构造 endl;}
const Test operator(const Test that){// 当ptr和that.ptr指向的内存块大小一样可以直接进行内存拷贝*ptr *that.ptr;cout 调用了赋值函数 endl;return *this;/*当对象的ptr指向的内存与与that.ptr指向的内存块不一样大先释放旧的ptr再分配新的要与that.ptr的内存块一样大然后再拷贝*/}
};
int main(int argc,const char* argv[])
{Test t1(1234); // 调用了普通的构造函数Test t2 t1; // 调用了拷贝构造t1 t2; // 调用的是赋值函数return 0;
}
浅拷贝与深拷贝
拷贝就是一个对象给另一个对象赋值编译器自动生成的拷贝构造和赋值函数执行的业务逻辑就是浅拷贝(成员指针给成员指针赋值)深拷贝就是把成员指针所指向的内存拷贝给另一个成员指针所指向的内存。
浅拷贝就是指针给指针赋值深拷贝就内存给内存赋值。
注意如果成员变量中没有成员指针则浅拷贝就可以满足需求如果如果成员变量中有成员指针且指向堆内存则必须手动实现深拷贝否则就会出现 double free or corruption 的错误。