C++中什么时候调用复制构造函数?
在C++中,复制构造函数(Copy Constructor)被用于创建一个新的对象,该对象是使用另一个对象作为参数,或通过另一个对象进行初始化得到的。该复制构造函数必须接受另一个对象的引用作为参数,否则它将不能正确地工作。复制构造函数还可以从派生类向基类进行类型转换。
下面,让我们看一些情况,它们触发了C++中复制构造函数的调用。
拷贝初始化
当使用一个对象来初始化另一个对象时,通常会调用复制构造函数。例如:
#include <iostream>
using namespace std;
class Rectangle {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(const Rectangle& rec) {
width = rec.width;
height = rec.height;
cout << "Copy constructor called" << endl;
}
};
int main() {
Rectangle rec1(10, 20);
Rectangle rec2 = rec1; // copy constructor called
Rectangle rec3(rec1); // copy constructor called
return 0;
}
在上面的示例中,创建了一个名为rec1
的Rectangle对象,这个对象的宽度是10,高度是20。然后,通过拷贝初始化方法,创建了另外两个Rectangle对象:rec2
和rec3
。在这里,复制构造函数被调用了两次,用于初始化rec2
和rec3
。
以值返回对象
当函数将一个对象作为返回值传递给它的调用者时,也会调用复制构造函数。
#include <iostream>
using namespace std;
class Rectangle {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(const Rectangle& rec) {
width = rec.width;
height = rec.height;
cout << "Copy constructor called" << endl;
}
};
Rectangle duplicate(Rectangle& rec) {
Rectangle duplicate_rec(rec.width, rec.height);
// do some modifications to the new object
return duplicate_rec; // copy constructor called
}
int main() {
Rectangle rec1(10, 20);
Rectangle rec2 = duplicate(rec1);
return 0;
}
在上面的示例中,duplicate()
函数将一个Rectangle
对象作为参数,并创建一个新的Rectangle
对象,该对象是通过以rec.width
和rec.height
初始化得到的。然后,函数执行一些修改,最终返回这个新的对象。在这里,复制构造函数被调用了一次,用于将新的对象返回给调用者。
通过一个对象初始化另一个对象
当一个对象通过另一个对象进行初始化时,也会调用复制构造函数。例如:
#include <iostream>
using namespace std;
class Rectangle {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(const Rectangle& rec) {
width = rec.width;
height = rec.height;
cout << "Copy constructor called" << endl;
}
};
int main() {
Rectangle rec1(10, 20);
Rectangle rec2(rec1);
return 0;
}
在上面的示例中,创建了一个名为rec1
的Rectangle
对象。然后,通过另一个Rectangle
对象rec2
,用rec1
初始化了它。在这里,复制构造函数被调用了一次,用于初始化rec2
。
数组赋值
当数组被赋值给另一个数组时,每个元素都将使用其对应的复制构造函数进行复制。例如:
#include <iostream>
using namespace std;
class Rectangle {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(constRectangle& rec) {
width = rec.width;
height = rec.height;
cout << "Copy constructor called" << endl;
}
};
int main() {
Rectangle rec1(10, 20);
Rectangle rec2(5, 5);
Rectangle arr[] = {rec1, rec2};
Rectangle arr_copy[2];
arr_copy[0] = arr[0]; // copy constructor called
arr_copy[1] = arr[1]; // copy constructor called
return 0;
}
在上面的示例中,创建了两个Rectangle
对象:rec1
和rec2
。然后,这两个对象被存储在一个数组arr
中。接下来,又创建了一个新数组arr_copy
,并将arr
的元素赋值给它。在这里,复制构造函数被调用了两次,用于复制arr
中的元素。
参数传递
当一个对象通过引用传递给函数时,该函数可能会调用复制构造函数。例如:
#include <iostream>
using namespace std;
class Rectangle {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(const Rectangle& rec) {
width = rec.width;
height = rec.height;
cout << "Copy constructor called" << endl;
}
};
void modify(Rectangle& rec) {
// do some modifications to the object
}
int main() {
Rectangle rec1(10, 20);
modify(rec1); // copy constructor called
return 0;
}
在上面的示例中,rec1
对象通过引用传递给modify()
函数。在这里,当rec1
被传递给函数时,复制构造函数被调用了一次。
基类和派生类
在C++中,一个派生类的对象可以隐式地转换为一个基类的对象。这个转换可能会调用复制构造函数。例如:
#include <iostream>
using namespace std;
class Shape {
public:
int x, y;
};
class Rectangle: public Shape {
public:
int width, height;
Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle(const Rectangle& rec) {
width = rec.width;
height = rec.height;
x = rec.x;
y = rec.y;
cout << "Copy constructor called" << endl;
}
};
int main() {
Rectangle rec(10, 20);
Shape shape = rec; // copy constructor called
return 0;
}
在上面的示例中,创建了一个名为rec
的Rectangle
对象,它的宽度为10,高度为20。然后,通过派生类Rectangle
,隐式地将它转换为基类Shape
的对象。在这里,复制构造函数被调用了一次,用于将rec
转换为shape
。
结论
在C++中,复制构造函数在以下情况下会被调用:
- 对象通过拷贝初始化方式创建。
- 对象通过一个对象初始化另一个对象。
- 从函数以值的方式返回一个对象。
- 数组赋值。
- 通过引用传递对象给函数。
- 派生类的对象隐式转换为基类的对象。
在理解这些场景后,我们可以更好地使用C++中的复制构造函数来优化我们的代码。