2017-08-02 4 views
0

私は考えることができるようにしようとしているものの例の 'シンプルな'ものとして私は以下を持っています。私は抽象クラスAを持っています。公開クラスは、operator==performTasksSpecificToAの2つのメソッドで公開されています。 AのユーザーがAの実装について心配する必要がないことを保証するために、「奇妙に繰り返されるテンプレートパターン」と同様に、「テンプレートメソッドパターン」を使用していることがわかります。つまり、AImplまだAImplという2つのインスタンスと同等かどうかをチェックすることができます。このアプローチに関するもう少し情報と文脈については、this answer on SOを参照してください。等価演算子定義で抽象クラスを使用しているときに、コードの重複を減らすために親クラスを定義するにはどうすればよいですか?

は今、私は次のようにクラスBを定義したいとします

class B 
{ 
    public: 
     virtual ~B() = 0; 

     bool operator(const B& b) const; 
     void performTasksSpecificToB(); 
}; 

あなたはサブクラスを比較するための公共operator==を定義するという点でAとして、クラスB株式同じ問題を見ることができるように。 ABの間にコードが重複しないように、親クラスを定義するにはどうすればLetterと呼びますか?


私のコンパイルして実行する私の '簡単な例'です。

#include <iostream> 

class A 
{ 
    public: 
     virtual ~A() = 0; 

     bool operator==(const A& a) const; 
     void performTasksSpecificToA(); 
    private: 
     virtual bool checkEquality_(const A& a) const = 0; 
}; 

template <class T> 
class A_ : public A 
{ 
    protected: 
     bool checkEquality_(const A& a) const override; 
    private: 
     virtual bool checkEquality(const T& t) const = 0; 
}; 

class AImpl : public A_<AImpl> 
{ 
    public: 
     AImpl(int val) : val(val){}; 
     bool checkEquality(const AImpl& anAImpl) const override; 
    private: 
     int val; 
}; 

A::~A(){} 

bool A::operator==(const A& a) const{ 
    return checkEquality_(a); 
} 

template <class T> 
bool A_<T>::checkEquality_(const A& a) const{ 
    const T* other = dynamic_cast<const T*>(&a); 
    if (other != nullptr){ 
     const T& me = static_cast<const T&>(*this); 
     return other->checkEquality(me); 
    } 
    return false; 
} 

bool AImpl::checkEquality(const AImpl& anAImpl) const{ 
    return val == anAImpl.val; 
} 

int main(){ 
    // factory: 
    AImpl* aImpl1 = new AImpl(1); 
    AImpl* aImpl2 = new AImpl(2); 
    AImpl* aImpl3 = new AImpl(1); 

    // client: 
    A& A1 = *aImpl1; 
    A& A2 = *aImpl2; 
    A& A3 = *aImpl3; 


    std::cout << "A1 == A2 -> "; 
    std::cout << (A1 == A2 ? "true" : "false"); 
    std::cout << std::endl; 


    std::cout << "A1 == A3 -> "; 
    std::cout << (A1 == A3 ? "true" : "false"); 
    std::cout << std::endl; 

    delete aImpl1; 
    delete aImpl2; 
    delete aImpl3; 
    return 0; 
} 
+0

なぜ等価比較でこのようなレベルの間接参照がありますか? –

+0

最初のレベルは 'A'をテンプレートクラスにすることを避けるためです:したがって、私は実際のロジックを' A_'に移動しました。 2番目のレベル、すなわち 'A :: checkEquality_'を使用するのは、公に公開されたメソッドと、サブクラスによって(「テンプレートメソッドパターン」ごとに)ライドされる必要のある部分とを区別するためです。 – wesanyer

答えて

0

あなたはLetterテンプレートことを可能にすることができれば、あなたは、単にテンプレートベースからA継承を持つことができます。

template<class T> 
class Letter 
{ 
public: 
    bool operator==(const Letter<T>& t) const { 
     const T& t1 = static_cast<const T&>(*this); 
     const T& t2 = static_cast<const T&>(t); 
     return t1.checkEquality_(t2); 
    } 
private: 
    virtual bool checkEquality_(const T& a) const = 0; 
}; 

class A : public Letter<A> 
{ 
    public: 
     virtual ~A() = 0; 
     void performTasksSpecificToA(); 
}; 
... 

あなたは絶対に共通Letterが必要な場合、あなたはおそらく別のレイヤーを追加する必要がありますがA_AのようにCRTPの

関連する問題