class Point{
private:
int x,y;
public:
Point(int x=0,int y=0):x(x),y(y){} // 合并构造函数
~Point(){}
// 拷贝构造函数保持不变
Point(const Point & others){
this->x=others.x;
this->y=others.y;
}
// 定义拷贝赋值操作符
Point& operator=(const Point &others) {
if (this != &others) {
this->x = others.x;
this->y = others.y;
}
return *this;
}
// 其他成员函数不变...
};
思考:只有一个拷贝构造函数不行吗?
回答:
在C++中,拷贝构造函数和拷贝赋值操作符虽然执行相似的操作——它们都用于从另一个对象复制数据——但它们在不同的情况下被调用,因此两者都需要定义以确保对象的正确拷贝。
拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它在下列情况下被调用:
- 通过使用另一个同类型对象进行初始化时。
Point p1; Point p2 = p1;
// 使用p1
初始化p2
。
- 当函数按值传递对象作为参数时。
- 当函数返回一个对象时(虽然大多数现代C++编译器会使用返回值优化(RVO)来避免这种拷贝)。
拷贝赋值操作符
拷贝赋值操作符是一个重载的赋值操作符,它在将一个对象赋值给另一个已经存在的对象时被调用。
Point p1; Point p2; p2 = p1;
// 调用拷贝赋值操作符。
两者之间的关键区别在于对象的生命周期阶段。拷贝构造函数在对象创建时用于初始化,而拷贝赋值操作符在对象已经存在时用于改变其状态。
为什么需要两者
定义拷贝赋值操作符而不定义拷贝构造函数(或反之)可能导致在需要拷贝对象时,对象的某些部分不被正确地复制。这是因为如果不显式定义这两个函数中的任何一个,编译器会为你生成一个默认的实现,但这个默认实现可能不适合你的需要,尤其是当对象包含动态分配的内存或其他需要“深拷贝”的资源时。
例如,如果一个类拥有指向动态分配内存的指针成员,仅仅使用编译器生成的默认拷贝赋值操作符和拷贝构造函数将导致两个对象指向相同的内存地址,这可能会在析构函数中导致双重释放同一内存块的问题。
简而言之,定义自己的拷贝构造函数和拷贝赋值操作符是为了确保对象的每一次复制都是按照你的具体需求来执行的,尤其是当对象的复制行为不是简单的位拷贝时。