C++中复制构造函数何时调用?什么时候需要自定义副本构造函数

C++ 专栏收录该内容
23 篇文章 0 订阅

什么是复制构造函数?

复制构造函数是一个成员函数,它使用同一个类的另一个对象初始化一个对象。函数原型如下:

ClassName(const ClassName &old_obj);

下面是一个复制构造函数的简单示例:

#include <iostream>
using std::cout;

class Point {
private:
    int x, y;
public:
    Point(int x1, int y1) { x = x1, y = y1; } //带参构造函数
    //复制构造函数
    Point(const Point& p) { x = p.x, y = p.y; }

    int getx() { return x; }
    int gety() { return y; }
};

int main()
{
    Point p1(10, 20);
    Point p2 = p1;
    cout << "\np2对象x和y的值分别是:\n" << p2.getx() << "  " << p2.gety();
    return 0;
}

**输出:**10,20

复制构造函数何时调用?

  1. 当类的对象按值返回时。(也就是把对象做为返回值,那接受对象的变量也必须是一个对象,所以会调用复制构造函数)
  2. 当类的对象通过值作为参数传递(传递给函数)时。因为函数按值传递是传副本。
  3. 根据同一个类的另一个对象构造一个对象时。
  4. 编译器生成临时对象时。

**但是,不能保证在所有这些情况都将调用复制构造函数,因为C++标准允许编译器在某些情况下优化复制,一个例子是返回值优化(有时称为RVO)。

什么时候需要用户定义的副本构造函数?

如果我们不定义自己的副本构造函数,则C++编译器会创建一个默认的,该类在对象之间进行成员级复制。编译器创建的复制构造函数通常可以正常工作。可当对象具有指针、文件句柄、网络连接等,才需要我们自己定义的复制构造函数。

默认构造函数仅执行浅复制
在这里插入图片描述

复制构造函数 与 赋值运算符
下面两个语句中,哪个调用复制构造函数?

MyClass t1,t2;
MyClass t3 = t1;  //-----> (1)
t2 = t1;  // ------> (2)

从现有对象创建新对象作为现有对象的副本时,将调用复制构造函数。
当以初始化的对象从另一个现有对象中分配新值时,将调用分配运算符。
所以,上面第一句调用复制构造函数,第二句调用赋值运算符。

下面是一个完整的C++程序,此例必须使用复制构造函数

#include <iostream>
using namespace std;

class String {
private:
    char* s;
    int size;
public:
    String(const char* str = NULL); //构造函数
    ~String() { delete[]s; } //析构函数
    String(const String&); //复制构造函数
    void print() { cout << s << endl; } //输出字符串
    void change(const char*); //改变功能
};

String::String(const char* str) {
    size = strlen(str);
    s = new char[size + 1];
    strcpy_s(s, size + 1, str);
}

void String::change(const char* str) {
    delete[]s;
    size = strlen(str);
    s = new char[size + 1];
    strcpy_s(s, size + 1, str);
}

String::String(const String& old_str) {
    size = old_str.size;
    s = new char[size + 1];
    strcpy_s(s, size + 1, old_str.s);
}

int main()
{
    String str1("俺蔡文姬打野贼6...."); //对象初始化
    String str2 = str1; //对象复制,调用复制构造函数

    str1.print(); //输出
    str2.print(); //输出

    str2.change("一看战绩0—5  "); //修改类成员值

    str1.print();
    str2.print();
    return 0;
}

如果从上面代码中删除复制构造函数,会出现上面问题?
无法获得预期的输出,对str2所做的修改也会反映在str1中

可以将复制构造函数设为私有吗?
可以把构造函数设为私有,这样此类的对象将变为不可复制。

为什么必须将复制构造函数的参数作为引用传递?
按值传递对象时,将调用复制构造函数。复制构造函数本身就是一个函数。因此,如果我们在复制构造函数中按值传递参数,则会对复制构造函数进行调用,以调用复制构造函数,这将成为一个无终止的调用链。所以,编译器不允许按值传递参数。

为什么复制构造函数的参数应该为 const ?
当我们创建自己的副本构造函数时,我们通过引用传递对象,并且通常将其作为const引用传递。传递const引用的原因之一是,以免意外修改对象。这是用const的一个很好的理由,但还有更多原因。

  • 16
    点赞
  • 0
    评论
  • 29
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值