为什么需要析构函数就几乎需要拷贝构造函数和拷贝赋值运算符?或者说拷贝构造函数和拷贝赋值运算符什么时候需要自己构造?
答:当类内出现指针时,为了防止浅拷贝,即只对指针变量进行拷贝,而不对指针指向的对象也进行复制。自定义拷贝构造函数是为了防止析构函数多次delete同一个指针对象,而自定义拷贝赋值运算符是为了防止在赋值后一个指针所指向对象改变值后不改变另一个指针对象的值。
需要自定义拷贝构造函数示例(可注释掉拷贝构造函数,看注释前后输出发生了什么变化)
// // Created by raysuner on 20-2-2. // #include <iostream> using namespace std; class A{ private: string *str; public: explicit A(const string &s){ cout << "构造函数" << endl; str = new string(s); } A(const A &a){ cout << "拷贝构造函数" << endl; this->str = new string(*a.str); } ~A() {delete str; cout << "析构函数" << endl;} void print(){ cout << *(this->str) << endl; } }; A f(A a){ A ret = a; /*一系列操作*/ return ret; } int main(){ A a("C++"); f(a); a.print(); return 0; }
需要自定义拷贝赋值运算符(可注释掉拷贝赋值运算符,看注释前后输出发生了什么变化)
#include <iostream> using namespace std; class A{ private: string *str; public: explicit A(const std::string &s = "hello world"){ str = new string(s); } A &operator=(const A &a){ if(this != &a) this->str = new string(*a.str); return *this; } ~A() {delete str;} void setValue(string s){ *str = s; } void print(){ cout << "地址:" << (this->str) << " 值:" << *(this->str) << endl; } }; int main(){ cout << "初始化对象" << endl << endl; A a("abcdefg"); A b; a.print(); b.print(); cout << "对象间赋值" << endl << endl; b = a; a.print(); b.print(); cout << "改变一个对象的值" << endl << endl; a.setValue("learning cpp is very interesting"); a.print(); b.print(); return 0; }
拷贝构造函数和拷贝赋值运算符分别在什么时候调用?
答:两者都是实现对象间的复制,但调用的条件略有差异,最关键的是看有没有新的对象生成
#include <iostream> using namespace std; class A{ public: A() {cout << "默认构造函数" << endl;} A(const A&) {cout << "拷贝构造函数" << endl;} A operator=(const A&) {cout << "拷贝赋值运算符" << endl;} }; int main(){ A a,b = a,c; //这里新生成了a, b, c三个对象,生成a和c会调用两次默认的构造函数,b在生成时被赋值,这时会调用拷贝构造 c = b; // 由于c在上面生成了,不算是新生成的对象,故在被拷贝赋值时调用赋值运算符 return 0; }
合成拷贝构造函数和合成拷贝赋值运算符什么情况下是被定义为删除的?
- 类的析构函数是被删除或者不可访问的(例如,是private的),则合成析构函数是不可访问的,则类合成的拷贝构造函数是被定义为删除的
- 拷贝构造函数是删除的或者不可访问的,则类合成的拷贝构造函数是被定义为删除的
- 类的某个拷贝赋值运算符是删除的或不可访问的,或是类有一个const成员或引用成员,则类的合成拷贝复制运算符是被定义为删除的
来源:https://www.cnblogs.com/raysuner/p/12273025.html