美文网首页c++学习笔记
c++复制构造函数

c++复制构造函数

作者: 檀香静雪 | 来源:发表于2020-07-12 18:13 被阅读0次

    基本概念

    复制构造函数(Copy constructor)是c++中的一个特殊构造函数,也称拷贝构造函数,它只有一个参数,参数类型为同类对象的引用。

    如果没有定义复制构造函数,那么编译器将生成默认的复制构造函数。默认的复制构造函数完成复制的功能。

    复制构造函数的参数为同类对象的引用,可以是常应用,也可以是非常引用。形如类名::类名(类名&)类名::类名(const 类名&)

    默认复制构造函数

    class Complex {//复数类
    public:
        double real, imag;//分别表示实部以及虚部
    public:
        //构造函数
        Complex(double r,double i) {
            real = r;
            imag = i;
        }
    };
    

    对于上面的复数类,假设我们有如下的初始化:

    int main() {
        Complex c1(5, 2);
        cout << "c1.real=" << c1.real << "\tc1.imag=" << c1.imag << endl;
        Complex c2(c1);//调用复制构造函数初始化c2
        cout << "c2.real=" << c2.real << "\tc2.imag=" << c2.imag << endl;
        return 0;
    }
    

    在上面的初始化工作中,我们调用构造函数对c1进行初始化工作,然后输出c1的实部以及虚部。然后用c1去初始化c2,此时将调用编译器自动生成的构造函数将c2初始化为和c1一样,然后输出c2的实部以及虚部。运行上面的程序,得到如下的输出:

    c1.real=5       c1.imag=2
    c2.real=5       c2.imag=2
    

    可以看到此时c2被初始化为和c1相同。

    编写复制构造函数

    在上面的例子中,我们并没有编写复制构造函数,此时编译器将生成一个默认的复制构造函数完成复制工作。

    当我们自己编写了复制构造函数之后,编译器将不再生成默认的复制构造函数。如下面的例子所示:

    class Complex {//复数类
    public:
        double real, imag;//分别表示实部以及虚部
        //构造函数
        Complex(double r,double i) {
            real = r;
            imag = i;
        }
        Complex(const Complex& c) {//复制构造函数
            real = c.real;
            imag = c.imag;
            cout << "调用复制构造函数!!" << endl;
        }
    };
    

    对于上面的类,在复制构造函数被调用的时候将完成复制的工作,并且向控制台输出调用复制构造函数!!,假设我们有如下的初始化:

    int main() {
        Complex c1(5, 2);
        cout << "c1.real=" << c1.real << "\tc1.imag=" << c1.imag << endl;
        Complex c2(c1);//调用复制构造函数初始化c2
        cout << "c2.real=" << c2.real << "\tc2.imag=" << c2.imag << endl;
        return 0;
    }
    

    执行后可以得到如下的结果:

    c1.real=5       c1.imag=2
    调用复制构造函数!!
    c2.real=5       c2.imag=2
    

    可以看到,此时我们自己编写的复制构造函数被调用,并且向屏幕输出了调用复制构造函数!!

    错误用法

    复制构造函数的参数一定要是对同类对象的引用,不能为其它的。

    class Complex {
    public:
        double real, imag;
        Complex(double r,double i) {
            real = r;
            imag = i;
        }
        Complex(Complex c) {//错误的写法
            real = c.real;
            imag = c.imag;
            cout << "调用复制构造函数!!" << endl;
        }
    };
    

    如上所示,我们错误的将参数Complex& c写为了Complex c,此时我们的编译将无法通过,在visual studio 2019中将得到以下的报错:

    error C2652: “Complex”: 非法的复制构造函数: 第一个参数不应是“Complex”
    message : 参见“Complex”的声明
    error C2333: “Complex::Complex”: 函数声明中有错误;跳过函数体
    error C2558: class“Complex”: 没有可用的复制构造函数或复制构造函数声明为“explicit”
    

    总之,复制构造函数的参数一定要是同类对象的引用

    复制构造函数起作用的情况

    用一个对象来初始化正在构造的对象变量

    如上面编写复制构造函数小节中所展示的那样,当我们用同类的一个对象去初始化另一个对象时,会导致构造函数被调用。

    需要注意的是:

    Complex c1(5, 2);
    Complex c2(c1);
    Complex c3 = c1;//初始化语句,非赋值语句
    

    上面的第三天语句为初始化语句,并非赋值语句。

    函数参数作为对象传值

    如果某函数有一个参数是类的对象,那么该函数被调用时,该类的复制构造函数将被调用。

    class Complex {//复数类
    public:
        Complex() {};
        Complex(const Complex& c) {//复制构造函数
            cout << "调用复制构造函数!!" << endl;
        }
    };
    

    对于上面的类,假设我们有如下调用:

    void fun(Complex c){}
    int main() {
        Complex c;
        fun(c);//调用fun(Complex c)
        return 0;
    }
    

    其中我们定义了一个函数fun(Complex c),其参数为一个Complex对象,当我们在调用fun(Complex c)的时候,形参c将被初始化,此时将调用复制构造函数完成初始化工作,产生如下的输出:

    调用复制构造函数!!
    

    需要注意的是,如果函数的参数为对象的引用或常引用时,将不会导致构造函数被调用,如下所示:

    void fun(Complex &c){}
    

    函数返回一个对象

    如果函数的返回值是某类的对象,则函数返回时,复制构造函数将被调用。

    class Complex {//复数类
    public:
        Complex() {};
        Complex(const Complex& c) {//复制构造函数
            cout << "调用复制构造函数!!" << endl;
        }
    };
    

    对于上面的类有如下调用:

    Complex fun(){
        Complex c(2,3);
        return c;
    }
    int main() {
        cout << fun().real << endl;
        return 0;
    }
    

    函数fun()返回一个Complex类的对象,在调用fun()函数时会导致复制构造函数被调用。

    注意事项

    • 上述情形未必会调用复制构造函数。因为C++标准允许编译器实现做一些优化。例如:Class X b=X();

    优化

    当对象作为函数参数,在对函数进行调用时会调用复制构造函数对形参进行初始化工作,此时会产生额外的开销,我们可以将函数的参数写为对象的引用来避免额外的开销,如果担心对象的值在函数中会被改变,我们也可以用常引用的方式。

    对于如下的写法:

    Complex fun(Complex c){}
    

    我们可以改写为:

    Complex fun(Complex& c){}
    Complex fun(const Complex& c) {}
    

    相关文章

      网友评论

        本文标题:c++复制构造函数

        本文链接:https://www.haomeiwen.com/subject/xrhncktx.html