条款12:复制对象时勿忘其每一个成分

1.前言

合格的面向对象系统会将对象的内部封装起来,只留下两个函数负责对象拷贝,即copy构造函数和copy assignment操作符,我统一称它们为copying函数

如果在class类里面声明自己的copy函数,意味着告诉编译器并不喜欢编译器自动生成的copy构造函数。此时编译器会u彷佛被冒犯,会以一种奇怪的方式回敬:当你的代码几乎必然出错时却不告诉你。如以下代码:

void logCall(sonst std::string& funcName);//生成个log entry

class Customer{

    public:
        ...
        Customer(const Custome& rhs);
        Customer& operator=(const Customer& rhs);
        ...
    private:
        std::string name;
};

Customer::Customer(const Customer& rhs):name(rhs.name)//复制rhs数据
{
    logCall("Customer copy constructor");
}
Customer& Customer::operator=(const Customer& rhs)
{
    logCall("Customer copy assignment operator");
    name=rhs.name;//复制rhs的数据
    return *this;//见条款10
}

1.1 出现错误时候的情况

这里的一切都看起来很好,直到另一个成员变加入战局:

class Date{....};//日期

class Custome{

    public:
        ....//同前
    private:
        std::string name;
        Date lastTransaction;
}

这段代码中,copy函数执行的是局部拷贝:只复制了顾客的name,但没有复制添加新的lastTransaction。但大多数编译器对此并不作出任何警报,因为程序员自写了copy构造函数。

因此,结论很明显:如果为class添加一个成员变量,必须同时修改copying构造函数。

再比如以下代码:

class PriorityCustomer:public Customer{

    public:
        ...
        PriorityCustomer(const PriorityCustomer& rhs);
        PriorityCustomer& operator=(const PriorityCustomer& rhs);
        ...
    private:
        int priority;
};

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):priority(rhs.priority)
{
    logCall("PriorityCustomer copy constructor");
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
    logCall("PriorityCustomer copy assignment operator");
    priority=rhs.priority;
    return *this;
}

在该代码中,PriorityCustomer的copying函数看起来复制了PriorityCustomer内的每一个成员变量。但这里,每个PriorityCustomer还内含它所继承的Customer成员变量复件,而那些成员变量却未被复制。PriorityCustomer的copy构造函数并没有指定实参传给其base class构造函数(即在它的成员初值列表中没有提到Customer)。因此PriorityCustomer对象的Customer成分会被不带实参的Customer构造函数初始化。以上事情在PriorityCustomer的copy assignment操作符轻微不同,它也并不打算修改其Base class的成员变量,所以那些成员变量保持不变。

2.正确修改方法

任何时候都必须小心的复制其base class的成员变量,那些成分往往是private,所以无法直接访问它们,应该让derived class的copy函数调用相应的base class函数:

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)
{
    logCall("PriorityCustomer copy constructor");
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
    logCall("PriorityCustomer copy assignment operator");
    Customer::operator=(rhs);//对baseClass成分进行赋值动作
    priority=rhs.priority;
    return *this;
}

这种修改方法可以说赋值了每一个成分,所以

(1)确保赋值所有local成员变量

(2)调用所有base classer内的适当copying函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值