2017-09-20 1 views
0

私はいくつかの抽象基底クラスを持ちたいと思っています。複数のクラスから継承しています。追加のクラスを宣言することなくオーバーライドされます。いくつかのデザインパターンを介してこれを実現するための方法がある場合複数の継承とオプションの関数のオーバーライドに関する推奨事項が必要です

A1 foo 
A2 foo 
Printing combinations 
A1 foo 
B bar 
A1 foo 
B1 bar wrapper begin 
B bar 
B1 bar wrapper end 
A2 foo 
B bar 
A2 foo 
B1 bar wrapper begin 
B bar 
B1 bar wrapper end 

、または:

#include <iostream> 

using namespace std; 

class A 
{ 
    public: 
     virtual void foo() = 0; 

    protected: 
     A() {} 
}; 

class A1 : public A 
{ 
    public: 
     A1() : A() {} 

     void foo() { cout << "A1 foo" << endl; }; 
}; 

class A2 : public A 
{ 
    public: 
     A2() : A() {} 

     void foo() { cout << "A2 foo" << endl; }; 
}; 

class B 
{ 
    public: 
     virtual void bar() { cout << "B bar: " << endl; } 
}; 

class B1 : public B 
{ 
    public: 
     void bar() 
     { 
      cout << "B1 bar wrapper begin" << endl; 
      B::bar(); 
      cout << "B1 bar wrapper end" << endl; 
     } 
}; 

/* 
    ??? 
    pure virtual class C 
    enforce derived classes to inherit something of type A 
    enforce derived classes to inherit something of type B 

    class C1 : public A1, either B or B1 ??? templates??? 
    { 

    } 

    class C2 : public A2, either B or B1 ??? templates??? 
    { 

    } 

    Can this be done without having to define classes CA1B, CA2B, CA1B1, CA2B1, etc.? 
*/ 

int main(int argc, char *argv[]) 
{ 
    A1 a1; 
    a1.foo(); 
    A2 a2; 
    a2.foo(); 

/* 
    C1 c1b with type B 
    C1 c1b1 with type B1 
    C2 c2b with type B 
    C2 c2b1 with type B1 

    put c1b, c1b1, c2b, c2b1 in a list named "combinations" 

    cout << "Printing combinations" << endl; 
    for (auto i : combinations) 
    { 
     i->foo(); 
     i->bar(); 
    } 
*/ 

    return 0; 
} 

理論的には、出力は次のようになります。私はここに私が達成しようとしているものの例をあげます私は悪いアプローチを使用しています、私に教えてください。私はC++ 11を使用しています。

答えて

3

ユースケースでは、「制約のあるテンプレート」が叫びます。あなたが欠けているのは、テンプレートパラメータが正しいクラスを継承しているかどうかをチェックしてエンコードする方法です。あなたはここにstd::is_base_of

template<class A_, class B_, 
     typename std::enable_if<std::is_base_of<A, A_>::value>, int>::type = 0, 
     typename std::enable_if<std::is_base_of<B, B_>::value>, int>::type = 0> 
class C : public A_, public B_ 
{ 

}; 

では、それがどのように動作するかだと行うことができます。それが供給され、ブール式が真のときに限り

std::enable_ifは、type(私たちの場合のようにint)を持つことになります。さもなければそこに型がなく、テンプレートはコンパイルされません。そこに型がある場合は、非型のテンプレートパラメータを取得しました。デフォルトの値は0です。デフォルトを割り当てると、2つの引数を使用してテンプレートをインスタンス化することができます。

これらのユーティリティは、<type_traits>ヘッダーにあります。

+0

このようなものは多態的に使用できますか?たとえば、あるオブジェクト 'shared_ptr ' 'とオブジェクト' shared_ptr > 'を作成した場合、その両方を' list >> 'に格納できますか?派生バージョンを 'C 'に変換するには、Cクラスで何が必要なのかよく分かりません。 – George

+0

@George - いいえ、テンプレートを使うか、明示的に(あなたの質問のように) 'C 'と 'C 'は多態性の関係にありません。 – StoryTeller

+0

@George - しかし、それらのクラスはすべて、 'B *'のコンテナまたは 'A *'のコンテナに入れることができます。 – StoryTeller

0

私はこの問題に興味がありましたが、私はいくつかの戦略を持っています。ソケットプログラムは、この種の抽象化の完璧なデモンストレーションだと私は思います。最も簡単なことの1つは、宣言したクラスの任意のオブジェクトで使用可能な関数と変数を持つ基本ヘッダを宣言することです。次に、ITSELFがテンプレート引数として設定されているときに、基本クラスを継承するクラスを作成します。例:

template<class P> class Socket { 
    protected: 
    int sock; 
    char datagram[4096]; 
    struct sockaddr_in server; 
    struct sockaddr_in b; 
    public: 
    void dport(int port){server.sin_port=htons(port);} 
    int CONNECT(){return connect(sock , (struct sockaddr *)&server , sizeof(server));}; 
    template <class Dst> inline void dst(Dst d){server.sin_addr.s_addr=inet_addr(d);} 
    template <class Src> void src(Src s){b.sin_addr.s_addr=inet_addr(s);} 
    int LISTEN(int port){b.sin_port=htons(port); return bind(sock, 
    (sockaddr*)&b, sizeof(b));} 

この時点で専門化する方法はいくつかあります。私のお気に入りは、独自の名前をテンプレート引数としてbaseに渡すことによって継承する新しいクラスを作成することです。 TCPソケットを使用しながら、

class UDP : public Socket<UDP> { 
public: 
    UDP(){server.sin_family=AF_INET; 
    this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);} 
    template <class Msg> int SEND(Msg m, int length){ 
    return sendto(this->sock, m, length, MSG_DONTWAIT, (sockaddr*)&this- 
    >server, sizeof(this->server));} 
    void RECV(void* buf, size_t size){socklen_t fromlen = sizeof(sockaddr); 
    ssize_t i = recvfrom(this->sock, buf, size, MSG_WAITALL, 
    (sockaddr*)&this->b, &fromlen);} 
}; 

class TCP : public Socket<TCP> { 
public: 
TCP(){this->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); this- 
>server.sin_family=AF_INET;} 
int SEND(std::string buf){return send(this->sock, buf.c_str(), buf.size(), 0);} //TODO: Error Handling 
void RECV(){char cur; while (read(this->sock, &cur, 1) > 0) {cout << cur;}}}; 

今すぐUDPソケットのrecvfrom()とはsendto()を使用)(送信()と読みます。これらの呼び出しのすべてが今有効です。

Socket<TCP> t1; 
Socket<UDP> u1; 
TCP t2; 
UDP u2; 

私はそれぞれ1でコードを複製せずに、基本クラスの特殊化を書くためにどのような方法を見つけ出すことができませんでした。派生クラスを作成する方が簡単です。

関連する問題