《Effective C++》条款12、继承中的拷贝和赋值

实现拷贝构造函数和赋值运算符时,我们不能遗忘任何一个成员,当我们自定义以上成员时,如果我们没有将其中的某个成员进行复制,编译器是没法检测出来的。这种情况下我们就会得到不正确的对象。所以当我们为某个类添加任何成员时,我们必须记得修改我们的拷贝构造函和复制运算符重载。

派生类的拷贝和赋值

在派生类中实现拷贝构造函数和复制运算符时我们不能遗忘基类成分,我们必须考虑我们派生类中的隐藏的基类成员的赋值。

考虑以下的案例:

class A {
public:
    A() : Num(0), Name("") {}
    A(int num, string name) :Num(num), Name(name) {}
    A(const A& a) :Num(a.Num), Name(a.Name) {};
    A& operator=(const A& a) {
        Num = a.Num;
        Name = a.Name;
        return *this;
    }

    void print()
    {
        cout << Num << " " << Name << " ";
    }

private:
    int Num;
    string Name;
};

class B:public A
{
public:
    B() :Dbl(0.0) {}
    B(int num,string name,double d) :A(num,name),Dbl(d) {}
    //拷贝构造
    B(const B& b):Dbl(b.Dbl) {}

    B& operator=(const B &b)
    {
        Dbl = b.Dbl;
        return *this;
    }

    void print() 
    {
        A::print();
        cout << Dbl << endl;
    }
private:
    double Dbl;

};

案例中B继承A,但是在B的拷贝成员中,没有考虑B中的A成员,于是当我们有如下的调用时,

    B b(1, "Bob", 1.0);
    B b1(b);
    b1.print();

我们将会在打印这样结果:
在这里插入图片描述
我们值是将b的Dbl成员拷贝给了b1,因此,对于b1的基类部分将会调用默认构造函数初始化。

所以我们的解决方案应该这样的,在派生类的拷贝构造函数初始化列表中调用基类的拷贝构造函数,在派生类的赋值运算符重载函数中调用基类的赋值运算符。

如下:

//拷贝构造,调用基类的拷贝构造函数
    B(const B& b):A(b),Dbl(b.Dbl) {}


B& operator=(const B &b)
    {
        A::operator=(b);//显示的调用基类的赋值运算符
        Dbl = b.Dbl;
        return *this;
    }

运行以下代码将会得到这样的结果:

B b(1, "Bob", 1.0);
B b1(b);
B b2;
b2 = b;
b1.print();
b2.print();

在这里插入图片描述

我们不能在赋值运算符中调用基类的拷贝构造函数,因为我们试图构造一个已经存在的对象,同样在拷贝构造函数中调用赋值运算符也没多大意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值