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

2021年3月16日12:49:41 发表评论 840 次浏览

我们已经讨论过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通过激烈的问题解决过程来训练和掌握这些概念。

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: