为什么拷贝构造函数的参数一定要拷贝

2020-08-09  本文已影响0人  奥利奥蘸墨水

测试

首先看测试用例:

#include <iostream>

using namespace std;

class Test{
public:
    Test():s("A"){}
    Test(string s):s(s){}
    Test(const Test &other){
        this->s = other.s;
        cout << "拷贝构造函数" << "+s:"<< other.s << endl;
    }
    void test(Test other){
        this->s = other.s;
        cout << "测试函数" << endl;
    }
    void print(){
        cout << s << endl;
    }

//    Test& operator=(Test other){
//        this->s = other.s;
//        cout << "等号的重载" << endl; 
//    }

    Test& operator=(const Test& other){
        this->s = other.s;
        cout << "等号的重载" << endl;
    }
private:
    string s;
};

int main(){
    Test A;
    Test B("B");
    A.print();
    B.print();

    A.test(B);
    A.print();

    Test C("C");
    A = C;
    A.print();
} 

运行结果:

A
B
拷贝构造函数+s:B
测试函数
B
拷贝构造函数+s:C
等号的重载

拷贝构造函数是否可以按值传递?

先分析一下这段代码,在Test类中有无参的构造函数,有参的构造函数,拷贝构造函数以及“=”的重载。

在输出中第一二个输出肯定是没有问题的,真正的重点要从第三个输出开始。可能乍一看不是很清楚第三个输出是怎么来的,但是细细分析还是可以猜出来的。
首先分析test这个函数,这个test函数的参数按值传参,那么在执行函数体之前会发生从实参到形参的一个转换,而这个转换要用到Test类的拷贝构造函数,即进行了Test(B)的一个操作,所以会存在第三行这样的输出。这样第四行和第五行的输出也就理所当然了。

结论

有了上面的分析我们就能解释为什么拷贝构造函数的参数只能使用引用了。因为如果拷贝构造函数的参数是按值传参,那么就会发生上面test函数那里发生的情况,调用拷贝构造函数,然后拷贝构造函数仍然是按值传参,那么继续调用拷贝构造函数,这样就会进入一个无限递归调用拷贝构造函数的bug。所以拷贝构造函数是必须按引用传递的。不按引用传递,直接编译不通过。

最后两行输出是“=”重载的一个测试,等号重载的参数是按照引用传递的,测试结果也与预期相符。

等号的重载是否可以按值传递?

现在将“=”重载函数换成被注释掉的按值传递的函数,结果也是能通过编译的,测试结果如下所示:

拷贝构造函数+s:C
等号的重载
C

从这个结果我们可以看到,从实参到形参形参的转换再次用了拷贝构造函数,其他部分没啥说的。

结论

所以说“=”号重载是可以用按值传递方式的,但是通常不采用,因为这样做会多以此拷贝,降低效率。

上一篇 下一篇

猜你喜欢

热点阅读