1

roundtrip2 つのポリシーを取るクラス テンプレートがあります。それらが異なる限り、すべて問題ありませんが、1 つのポリシーを 2 回使用すると、コンパイル エラーが発生します。

例:

#include <iostream>

class walk {
protected:
    void move() {
        std::cout<<"i'm walking."<<std::endl;
    }
};

class car {
protected:
    void move() {
        std::cout<<"i'm driving in a car."<<std::endl;
    }
};

template<typename S, typename T>
class roundtrip : private S, private T {
public:
    void printSchedule(void) {
        std::cout<<"away: ";
        S::move();

        std::cout<<"return: ";
        T::move();
    }
};

int main(void){
    roundtrip<walk,car> LazyTrip;
    LazyTrip.printSchedule();

    roundtrip<car,car> VeryLazyTrip; // ERROR: error: duplicate base type ‘walk’ invalid
    VeryLazyTrip.printSchedule();

    return 0;
}

それはどのように解決できますか?または、同じ動作を実現するためのより良い設計はありますか?

編集: ポリシーにラッパーを追加しましたが、ユーザー インターフェイスは変わりません。このソリューションについてどう思いますか? クリーンなデザインですか?

template<typename T>
class outbound : private T {
protected:
    void moveOutbound(void) {
        T::move();
    }
};

template<typename T>
class inbound : private T {
protected:
    void moveInbound(void) {
        T::move();
    }
};

template<typename S, typename T>
class roundtrip : private outbound<S>, private inbound<T> {
public:
    void printSchedule(void) {
        std::cout<<"away: ";
        this->moveOutbound();

        std::cout<<"return: ";
        this->moveInbound();
    }
};
4

3 に答える 3

2

継承する代わりに、データ メンバを に追加することもできますが、とroundtripの関数は現在. 関数を inおよびpublic にできない場合は、次のことができます。walkcarprotectedwalkcar

  • roundtripテンプレと仲良くなる

    class walk {
    protected:
        void move() {
            std::cout<<"i'm walking."<<std::endl;
        }
        template<class T, class S>
        friend class roundtrip;
    };
    
  • roundtripヘルパー クラスを介してメンバー関数にアクセスできるようにします。

    template<typename S, typename T>
    class roundtrip {
    private:
        struct helperT : private T
        {
        public: // or private + friend roundtrip
            using T::move;
            using T::T;
        } mT;
    
        struct helperS : private S
        {
        public:
            using S::move;
            using S::S;
        } mS;
    
    public:
        void printSchedule(void) {
            std::cout<<"away: ";
            mT.move();
    
            std::cout<<"return: ";
            mS.move();
        }
    };
    

    両方の型でインターフェイスが同じである場合は、2 つのヘルパー クラスの代わりにヘルパー クラス テンプレートを使用できます。

    template<typename S, typename T>
    class roundtrip {
    private:
        template<class U>
        struct helper : private U
        {
        public: // or private + friend roundtrip
            using U::move;
            using U::U;
        };
    
        helper<S> mS;
        helper<T> mT;
    
    public:
        void printSchedule(void) {
            std::cout<<"away: ";
            mT.move();
    
            std::cout<<"return: ";
            mS.move();
        }
    };
    

    (ヘルパー テンプレートの特殊化から継承することも可能です。たとえば、class roundtrip : helperT<T>, helperS<S>)

于 2013-11-14T16:34:22.870 に答える
1

DyPが気づいたように、これで十分です。

template<typename S, typename T>
class roundtrip {
    public:
    void printSchedule(void) {
        std::cout<<"away: ";
        awayPolicy.move();

        std::cout<<"return: ";
        returnPolicy.move();
    }

    private:
    T awayPolicy;
    S returnPolicy;
};

しかし、これにはmoveメソッドの作成が必要publicです。staticそれらを およびにすることもできるpublicため、インスタンス フィールドは必要ありません。

class walk {
public:
    static void move() {
    std::cout<<"i'm walking."<<std::endl;
    }
};

// the same for car

template<typename S, typename T>
class roundtrip {
    public:
    void printSchedule(void) {
        std::cout<<"away: ";
        S::move();

        std::cout<<"return: ";
        T::move();
    }
};

基本クラスの作成を検討することもできます。

class travelPolicy
{
public:
    virtual void move() = 0;        
    //...
};

carそれに由来walkする。次に、roundtripクラスはコンストラクターを介して両方のポリシーを受け入れ、printScheduleポインターを介してそれらを使用できます。

class roundtrip 
{
public:
    roundtrip(
        std::shared_ptr<travelpolicy> awayPolicy,
        std::shared_ptr<travelpolicy> returnPolicy)
    {
        this->awayPolicy = awayPolicy;
        this->returnPolicy = returnPolicy;
    }


    void printSchedule(void) 
    {
        std::cout<<"away: ";
        awayPolicy->move();

        std::cout<<"return: ";
        returnPolicy->move();
    }

private:
    std::shared_ptr<travelPolicy> awayPolicy;
    std::shared_ptr<travelPolicy> returnPolicy;
};

UPDATE(OPの編集に対応):

あなたの解決策は一般的には問題ありませんが、それでも継承を使いすぎているようです。A継承するとは、sBであるという言い方です。ここでは、そうではないことは確かです。プライベート継承の「ハック」により、このぎこちなさは目に見えなくなりますが、それが私には受け入れられるように思われる理由です。B A

于 2013-11-14T16:10:29.197 に答える
0

同一の基本クラスのケースに特化してみませんか? 可能であれば、私の代わりにブーストの mpl::if_ と c++11 またはブーストの type_trait の is_same を使用していました。手元にコンパイラがないため、以下の構文の問題がある可能性があります

#include <type_traits>

template<typename S, typename T>
class roundtrip_diff : private S, private T {
public:
    void printSchedule(void) {
        std::cout<<"away: ";
        S::move();

        std::cout<<"return: ";
        T::move();
    }
};

template<typename S>
class roundtrip_same : private S {
public:
    void printSchedule(void) {
        std::cout<<"away: ";
        S::move();

        std::cout<<"return: ";
        S::move();
    }
};

template<bool, typename True, typename False> struct if_{ typedef True type; };

template<typename True, typename False> struct if_<false,True,False> { typedef False type; };

template<typename A, typename B> struct is_same { enum{value=0}; };
template<typename A> struct is_same<A,A> { enum{value=1}; };

template<typename S, typename T>
class roundtrip : if_< is_same<S,T>::value, roundtrip_same<S>, roundtrip_diff<S,T> >::type { };

明らかに、任意の数の引数を許可する場合は、より洗練された解決策を見つける必要がありますが、これにより、重複した塩基のエラーが解消されるはずです。

于 2013-11-14T16:43:37.033 に答える