C++中的复制构造函数经典指南

我们已经讨论过C ++构造函数简介。在本文中, 讨论了复制构造函数。
什么是复制构造函数?
复制构造函数是一个成员函数, 它使用同一类的另一个对象初始化一个对象。复制构造函数具有以下常规函数原型:

ClassName (const ClassName & old_obj);

以下是复制构造函数的一个简单示例。
#include< iostream> using namespace std; class Point { private : int x, y; public : Point( int x1, int y1) { x = x1; y = y1; }// Copy constructor Point( const Point & p2) {x = p2.x; y = p2.y; }int getX(){return x; } int getY(){return y; } }; int main() { Point p1(10, 15); // Normal constructor is called here Point p2 = p1; // Copy constructor is called here// Let us access values assigned by constructors cout < < "p1.x = " < < p1.getX() < < ", p1.y = " < < p1.getY(); cout < < "\np2.x = " < < p2.getX() < < ", p2.y = " < < p2.getY(); return 0; }

输出如下:
p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15

复制构造函数何时调用?
在C ++中, 在以下情况下可以调用复制构造函数:
1.按值返回类的对象时。
2.当类的对象通过值作为参数传递(传递给函数)时。
3.基于同一类的另一个对象构造一个对象时。
4.编译器生成临时对象时。
但是, 不能保证在所有这些情况下都将调用复制构造函数, 因为C ++ Standard允许编译器在某些情况下优化复制, 例如:
返回值优化(有时称为RVO)
.
资源:
什么时候需要用户定义的副本构造函数?
如果我们不定义自己的副本构造函数, 则C ++编译器会为每个类创建一个默认的副本构造函数, 该类在对象之间进行成员级复制。编译器创建的副本构造函数通常可以正常工作。仅当对象具有指针或资源的任何运行时分配(如文件句柄, 网络连接等)时, 才需要定义我们自己的副本构造函数。
默认构造函数仅执行浅表复制。
C++中的复制构造函数经典指南

文章图片
【C++中的复制构造函数经典指南】只有用户定义的副本构造函数才能进行深层复制。
在用户定义的副本构造函数中, 我们确保已复制对象的指针(或引用)指向新的内存位置。
C++中的复制构造函数经典指南

文章图片
复制构造函数与赋值运算符
以下两个语句中的哪一个调用复制构造函数, 而哪个调用赋值运算符?
MyClass t1, t2; MyClass t3 = t1; // ----> (1) t2 = t1; // -----> (2)

从现有对象创建新对象作为现有对象的副本时, 将调用复制构造函数。当已初始化的对象从另一个现有对象中分配了新值时, 将调用赋值运算符。在上面的示例中, (1)调用复制构造函数, (2)调用赋值运算符。看到这个更多细节。
写一个需要复制构造函数的示例类吗?
以下是一个完整的C ++程序, 以演示Copy构造函数的用法。在下面的String类中, 我们必须编写副本构造函数。
#include< iostream> #include< cstring> using namespace std; class String { private : char *s; int size; public : String( const char *str = NULL); // constructor ~String() { delete [] s; } // destructor String( const String& ); // copy constructor void print() { cout < < s < < endl; } // Function to print string void change( const char *); // Function to change }; String::String( const char *str) { size = strlen (str); s = new char [size+1]; strcpy (s, str); }void String::change( const char *str) { delete [] s; size = strlen (str); s = new char [size+1]; strcpy (s, str); }String::String( const String& old_str) { size = old_str.size; s = new char [size+1]; strcpy (s, old_str.s); }int main() { String str1( "GeeksQuiz" ); String str2 = str1; str1.print(); // what is printed ? str2.print(); str2.change( "lsbin" ); str1.print(); // what is printed now ? str2.print(); return 0; }

输出如下:
GeeksQuiz GeeksQuiz GeeksQuiz lsbin

如果我们从上述代码中删除复制构造函数, 那将会是什么问题?
如果从上述程序中删除复制构造函数, 则不会获得预期的输出。对str2所做的更改也反映在str1中, 这是意料之外的。
#include< iostream> #include< cstring> using namespace std; class String { private : char *s; int size; public : String( const char *str = NULL); // constructor ~String() { delete [] s; } // destructor void print() { cout < < s < < endl; } void change( const char *); // Function to change }; String::String( const char *str) { size = strlen (str); s = new char [size+1]; strcpy (s, str); }void String::change( const char *str) { delete [] s; size = strlen (str); s = new char [size+1]; strcpy (s, str); }int main() { String str1( "GeeksQuiz" ); String str2 = str1; str1.print(); // what is printed ? str2.print(); str2.change( "lsbin" ); str1.print(); // what is printed now ? str2.print(); return 0; }

输出如下:
GeeksQuiz GeeksQuiz lsbin lsbin

我们可以将复制构造函数设为私有吗?
是的, 可以将复制构造函数设为私有。当我们将复制构造函数设为一个类私有时, 该类的对象将变为不可复制。当我们的类具有指针或动态分配的资源时, 这特别有用。在这种情况下, 我们可以像上面的String示例一样编写我们自己的副本构造函数, 也可以创建一个私有副本构造函数, 以便用户获得编译器错误, 而不是在运行时感到意外。
为什么必须将复制构造函数的参数作为引用传递?
按值传递对象时, 将调用复制构造函数。复制构造函数本身就是一个函数。因此, 如果我们在复制构造函数中按值传递参数, 则将对复制构造函数进行调用以调用复制构造函数, 这将成为一个无终止的调用链。因此, 编译器不允许参数按值传递。
为什么复制构造函数的参数应为const?
如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。
被认为是行业中最受欢迎的技能之一, 我们拥有自己的编码基础C ++ STL通过激烈的问题解决过程来训练和掌握这些概念。

    推荐阅读