C++ 复制构造函数和重载 = 运算符的情况
C++ Copy Constructor and cases of Overloadin the = operator
在下面的代码中 d = a;
没有调用复制构造函数。
a 是如何复制到 d 的?或者在什么情况下我们必须重载=运算符?
#include<iostream>
using namespace std;
class code{
int id;
public:
code(){}//default constructor
code(int a){
id=a;
}
code(code & x){//copy constructor
id=x.id;
}
void display(){
cout<<id;
}
};
int main(){
code a(100);
code b(a);//copy constructor is called
code c=a;//copy constructor is called again
code d;
c=a;//copy constructor is not called this time
std::cout << "\n id of A: ";
a.display();
cout << "\n id of B: ";
b.display();
cout << "\n id of C: ";
c.display();
cout << "\n id of D: ";
d.display();
return 0;
}
如何有效地实现复制构造函数?
没有调用复制构造函数,因为调用了隐式定义的复制赋值运算符。它的形式是:
T& T::operator=(const T&)
初始化时可以调用拷贝构造函数:
code d = a;
在您的代码中:
code d;
d = a;
正在调用 operator=
。
How The a is copied to d ?
使用复制赋值运算符。复制构造函数用于初始化,而不是赋值。
In what cases we have to Overload the = operator ?
当您需要不同于递归复制每个子对象的默认行为时。在您的情况下,默认行为是简单地复制 id
值。这也是复制构造函数的默认行为,因此您也不需要提供它。
Rule of Three 是您何时需要提供这些运算符的良好指南。当您的 class 管理另一个资源的生命周期时,您通常需要它们,该资源在其析构函数中释放。您需要非标准的复制语义,这样您就不会得到两个对象试图释放相同的资源。
根据 C++ 标准(12.8 复制和移动 class 个对象)
18 如果 class 定义没有显式声明复制赋值运算符,则隐式声明一个。如果 class 定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认 (8.4)。如果 class 具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。 class X 的隐式声明的复制赋值运算符将具有
形式
28 非联合 class X 的隐式定义 copy/move 赋值运算符对其子对象 执行成员 copy-/move 赋值。
在此声明中
c=a;
使用编译器复制赋值运算符隐式定义,因为 class 没有显式定义它,它执行对象数据成员的成员复制(对于这个 class 定义它是数据成员 int id;
)
当对象子对象的成员方式复制不满足class要求时,您需要显式定义复制赋值运算符。
在下面的代码中 d = a;
没有调用复制构造函数。
a 是如何复制到 d 的?或者在什么情况下我们必须重载=运算符?
#include<iostream>
using namespace std;
class code{
int id;
public:
code(){}//default constructor
code(int a){
id=a;
}
code(code & x){//copy constructor
id=x.id;
}
void display(){
cout<<id;
}
};
int main(){
code a(100);
code b(a);//copy constructor is called
code c=a;//copy constructor is called again
code d;
c=a;//copy constructor is not called this time
std::cout << "\n id of A: ";
a.display();
cout << "\n id of B: ";
b.display();
cout << "\n id of C: ";
c.display();
cout << "\n id of D: ";
d.display();
return 0;
}
如何有效地实现复制构造函数?
没有调用复制构造函数,因为调用了隐式定义的复制赋值运算符。它的形式是:
T& T::operator=(const T&)
初始化时可以调用拷贝构造函数:
code d = a;
在您的代码中:
code d;
d = a;
正在调用 operator=
。
How The a is copied to d ?
使用复制赋值运算符。复制构造函数用于初始化,而不是赋值。
In what cases we have to Overload the = operator ?
当您需要不同于递归复制每个子对象的默认行为时。在您的情况下,默认行为是简单地复制 id
值。这也是复制构造函数的默认行为,因此您也不需要提供它。
Rule of Three 是您何时需要提供这些运算符的良好指南。当您的 class 管理另一个资源的生命周期时,您通常需要它们,该资源在其析构函数中释放。您需要非标准的复制语义,这样您就不会得到两个对象试图释放相同的资源。
根据 C++ 标准(12.8 复制和移动 class 个对象)
18 如果 class 定义没有显式声明复制赋值运算符,则隐式声明一个。如果 class 定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认 (8.4)。如果 class 具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。 class X 的隐式声明的复制赋值运算符将具有
形式28 非联合 class X 的隐式定义 copy/move 赋值运算符对其子对象 执行成员 copy-/move 赋值。
在此声明中
c=a;
使用编译器复制赋值运算符隐式定义,因为 class 没有显式定义它,它执行对象数据成员的成员复制(对于这个 class 定义它是数据成员 int id;
)
当对象子对象的成员方式复制不满足class要求时,您需要显式定义复制赋值运算符。