我们已经讨论过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 ++编译器会为每个类创建一个默认的副本构造函数, 该类在对象之间进行成员级复制。编译器创建的副本构造函数通常可以正常工作。仅当对象具有指针或资源的任何运行时分配(如文件句柄, 网络连接等)时, 才需要定义我们自己的副本构造函数。
默认构造函数仅执行浅表复制。
只有用户定义的副本构造函数才能进行深层复制。
在用户定义的副本构造函数中, 我们确保已复制对象的指针(或引用)指向新的内存位置。
复制构造函数与赋值运算符
以下两个语句中的哪一个调用复制构造函数, 而哪个调用赋值运算符?
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通过激烈的问题解决过程来训练和掌握这些概念。