0

この 2 つのクラスがあり、スワップ イディオムが実装されているとします。基底クラスのコピー コンストラクターと代入演算子は、意味がないため削除されます。ただし、メンバーを保持するため、スワップメソッドが実装されています。

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 を交換できますが、派生オブジェクトのデータ メンバーは同じままです。

では、抽象クラスのスワッピングは外部から可能であってはならないという考えでよろしいでしょうか?

4

1 に答える 1

2

基底クラスのコピー コンストラクターと代入演算子は、意味がないため削除されます。

実際、これはひどいです。これでコピー不可になりDerivedました!なんで?この制限を追加する理由はありません。のデフォルトのコピー コンストラクターと代入演算子はBase、階層の最も基本的なクラスをコピーするというコンテキストでは完全に合理的です。

std::swap(derived1, derived2)元に戻すと、すでに正しいことを行っているので、他に何もする必要はありません。デフォルトの移動の構築/操作は正しいです。コンパイラに何かを任せるのは常に良いことです。

ただし、とにかくオーバーライドしたい場合はswap、それを行う正しい方法は、非メンバーの友人として行うことです。

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コピー コンストラクターは意味がありません。私の答えの最初の段落に従ってそれを削除してください。

于 2015-09-02T21:26:30.370 に答える