具有私有数据成员的抽象类的交换 - 成语

时间:2015-09-02 20:44:16

标签: c++ inheritance abstract copy-and-swap

假设我们有两个类,实现了swap-idioms。删除基类的复制构造函数和赋值运算符,因为它没有意义。但是实现了swap-method,因为它拥有一个成员。

namespace std
{
    template<>
    void swap<Base>(Base& a, Base& b)
    {
        a.swap(b);
    }

    template<>
    void swap<Derived>(Derived& a, Derived& b)
    {
        a.swap(b);
    }
}

class Base
{
public:
    Base(int ID) : ID_(ID) {}
    virtual std::string getString()=0;

    Base(const Base&)=delete;
    operator=(const Base&)=delete;

    void swap(Base& rhs)
    {
        std:swap(ID_, rhs.ID_);
    }
private:
    int ID_;
}

class Derived : public Base
{
public:
    Derived(int ID, bool Value) : Base(ID), Value_(Value) {}
    virtual ~Derived() {}
    Derived(Derived& rhs)
    {
        std::swap(*this, rhs);
    }

    virtual std::string getString() {return Value_ ? "True" : "False"}
    void swap(Derived& lhs, Derived& rhs)
    {
        std::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
        std::swap(lhs.Value_, rhs.Value_);
    }
private:
    bool Value_;
}

正如许多例子中所见,这是我想的标准方法。 但是,我发现公共Base :: swap存在问题,因为它不应该只交换抽象基类!

删除Base类的模板并使Base :: swap方法受保护不是更好:

class Base
{
    ...
protected:
    void swap(Base& rhs, Base &lhs);
}

class Derived : public Base
{
    ...
public:
    void swap(Derived& lhs, Derived& rhs)
    {
        Base::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
        std::swap(lhs.Value_, rhs.Value_);
    }
}

假设有另一个派生自base的类,第一个实现可以交换ID,但派生对象的数据成员将保持不变。

那么,我是否正确地认为不应该从外部交换抽象类?

1 个答案:

答案 0 :(得分:1)

  

删除基类的复制构造函数和赋值运算符,因为它没有任何意义。

实际上,这太可怕了。现在你让Derived不可复制了!为什么?没有理由添加此限制。 Base的默认复制构造函数和赋值运算符在复制层次结构的最基类的上下文中是完全合理的。

一旦你撤消了它,就没有必要做任何其他事情,因为std::swap(derived1, derived2)已经做了正确的事情。默认的移动构造/操作是正确的。让编译器为你做的事总是好的。

但是如果你想要覆盖swap,那么正确的方法就是non-member friend

class Base { 
   ...
   friend void swap(Base& lhs, Base& rhs) {
       using std::swap;
       swap(lhs.ID_, rhs.ID_);
   }
};

class Derived : public Base {
   ...
   friend void swap(Derived& lhs, Derived& rhs) {
       using std::swap;
       swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs));
       swap(lhs.Value_, rhs.Value_);
   }
};

此外,您的Derived复制构造函数毫无意义。按照我的答案的第一段删除它。