zoukankan      html  css  js  c++  java
  • effective C++ 条款 12:复制对象时勿忘其每一个成分

    copy构造函数和copy assignment操作符,我们称他们为copying函数。这些“编译器生成版”的行为:将被烤对象的所有成员变量

    都做一份拷贝。

    声明自己的copying函数,

    void logCall(const std::string funcName);
    class Customer
    {
    public:
        Customer(const Customer& rhs);
        Customer& operator=(const Customer& rhs);
    protected:
    private:
        std::string name;
    };

    Customer::Customer(const Customer& rhs)
    :name(rhs.name)
    {
        logCall("Customer copy constructor");
    }

    Customer& Customer::operator =(const Customer& rhs)
    {
        logCall("Customer copy assignment operator");
        name = rhs.name;
        return *this;
    }

    这里每件事情看起来都很好,实际上每件事情也的确很好,知道另一个成员变量加入:

    class Date{...};
    class Customer
    {
    public:
        Customer(const Customer& rhs);
        Customer& operator=(const Customer& rhs);
    protected:
    private:
        std::string name;
        Date lastTransaction;
    };

    这时既有的copying函数就是局部拷贝:他们的确复制了name但没有复制新添加的lastTransaction。如果你为class添加一个成员变量,你必须同时修改copying函数。(你也需要修改所有的构造函数以及任何非标准形式的operator=)。

    一旦发生继承,可能会造成此一主题最暗中肆虐的一个潜藏危机。试考虑:

    class PriorityCustomer : public Customer
    {
    public:
        PriorityCustomer(const PriorityCustomer& rhs);
        PriorityCustomer& operator=(const PriorityCustomer& rhs);
    protected:
    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构造函数,因此PriorityCustomer对象的Customer成分会被不带实参的default构造函数初始化。default构造函数将对name和lastTransaction执行缺省的初始化动作。

    base class 的成分往往是private, 所以你无法直接访问他们,你应该让derived class的copying函数调用相应的base class函数:

    PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
    :Customer(rhs),                //调用base class的copy构造函数
    priority(rhs.priority)
    {
        logCall("PriorityCustomer copy constructor");
    }
    PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
    {
        logCall("PriorityCustomer copy assignment operator");
        Customer::operator =(rhs);                //对base class成分进行赋值动作
        priority = rhs.priority;
        return *this;
    }

    当你编写一个copying函数,请确保1.复制所有的local成员变量,2.调用所有的base class内的适当的copying函数

    当这两个copying函数有近似相同的实现本体,令一个copying函数调用另一个copying函数无法让你达到你想要的目标。

    令copy assignment调用copy构造函数是不合理的,因为这像试图构造一个已经存在的对象。

    反方向令copy构造函数调用copy assignment操作符,同样无意义,相当于在一个未构造好的对象赋值。

    消除重复代码的做法是:建立一个新的成员函数给两者调用。这样的函数往往是private而且常被命名为init

  • 相关阅读:
    母函数详解
    java中为什么要实现序列化,什么时候实现序列化?
    cocos2dx&cocosbuilder折腾记
    Unity3D系列教程–使用免费工具在Unity3D中开发2D游戏 第二节(下)
    分頁查詢
    獲取CPU,硬盤序列號
    spcomm
    dbgrideh的導入和導出
    程序窗体及控件自适应分辨率
    組合的藝術
  • 原文地址:https://www.cnblogs.com/lidan/p/2322098.html
Copyright © 2011-2022 走看看