在operator=或拷贝构造中对所有数据成员赋值


1. operator=赋值操作符


Effective C++条款16中描述到,在派生类中重写赋值操作符函数时,要注意不要忘记对基类对象部分也要赋值,而这一点恐怕是许多新手容易忘记的,他们很自然地不会想到这一点(例如我),比如下述代码:

class CBase
{
public:
    CBase& operator=(const CBase& another)
    {
        if (this!=&another)
        {
            base=another.base;
        }
        return *this;
    }
    CBase(int a):base(a){}
    int Value(){return base;}
protected:
    int base;
};

class CDerived : public CBase
{
public:
    CDerived& operator=(const CDerived& another)
    {
        if (this == &another)
        {
            return *this;
        }
        // call baseclass's operator=
        //CBase::operator=(another);

        derived=another.derived;

        return *this;
    }
    CDerived(int b):derived(b),CBase(b){}
    int Value(){return derived;}
    int BaseValue(){return base;}
private:
    int derived;
};

int main()
{
    CDerived d1(3);
    cout<<"Derived Object 1: Base:"<<d1.BaseValue()<<"\t"<<"Derived:"<<d1.Value()<<"\n";

    CDerived d2(4);
    cout<<"Derived Object 1: Base:"<<d2.BaseValue()<<"\t"<<"Derived:"<<d2.Value()<<"\n";

    d1=d2;
    cout<<"After Assignment: Base:"<<d1.BaseValue()<<"\t"<<"Derived:"<<d1.Value()<<"\n";

    return 0;
}

上述例子中,派生类CDerived的赋值操作符函数没有将基类CBase对象部分的成员赋值,则基类对象的成员base仍然维持原值, 输出为:

Derived Object 1: Base:3  Derived:3
Derived Object 2: Base:4  Derived:4
After Assignment: Base:3  Derived:4

 如果将CBase::operator=(another);这一行的注释去掉,则可以成功将基类对象部分的成员进行赋值: 

Derived Object 1: Base:3  Derived:3
Derived Object 2: Base:4  Derived:4
After Assignment: Base:4  Derived:4



 

2. 拷贝构造函数

同样地,拷贝构造函数中也要注意调用基类版本的拷贝构造函数,这样才可以达到完全复制的目的:

class CBase
{
public:
    CBase& operator=(const CBase& another)
    {
        if (this!=&another)
        {
            base=another.base;
        }
        return *this;
    }
    CBase(const CBase& another):base(another.base){}
    CBase(int a=0):base(a){}
    int Value(){return base;}
protected:
    int base;
};

class CDerived : public CBase
{
public:
    //Version1:CDerived(const CDerived& another):derived(another.derived){}
    //Version2:CDerived(const CDerived& another):derived(another.derived),CBase(another){}
    CDerived& operator=(const CDerived& another)
    {
        if (this == &another)
        {
            return *this;
        }
        // call baseclass's operator=
        //CBase::operator=(another);
        
        derived=another.derived;
        
        return *this;
    }
    CDerived(int b=1):derived(b),CBase(b){}
    int Value(){return derived;}
    int BaseValue(){return base;}
private:
    int derived;
};

int main()
{
    CDerived d1(3);
    cout<<"Derived Object 1: Base:"<<d1.BaseValue()<<"\t"<<"Derived:"<<d1.Value()<<"\n";
    
    CDerived d2(d1);
    cout<<"After Copy Construction: Base:"<<d2.BaseValue()<<"\t"<<"Derived:"<<d2.Value()<<"\n";
    
    return 0;
}

如果派生类拷贝构造函数采用上例中Version1版本,则输出为:

Derived Object 1: Base:3        Derived:3
After Copy Construction: Base:0 Derived:3

基类部分的变量base没有被拷贝,实际上,基类部分的初始化是通过调用基类默认构造函数完成的,因此base的值为0

如果派生类拷贝构造函数采用上例中Version2版本,则输出为:

Derived Object 1: Base:3        Derived:3
After Copy Construction: Base:3 Derived:3

这样就达到了拷贝对象的目的。


总结


对于生成对象的三个函数:构造函数,拷贝构造函数和operator=函数,我们不仅仅要关注派生类成员变量的赋值或初始化,也要关注基类成员变量,不能遗漏。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值