7

親クラス()といくつかの子クラス()があるthisように、jQueryを可能にするためにクラス内のミューテーター(セッター)を戻したいと思います。ほとんどのもののミューテーターはクラスから継承されますが(名前やアドレスなど)、オブジェクトを返すため、クライアントミューテーターを呼び出すことはできません。a.name("something").address("somethingelse");EntityClient, Agent etc.EntityEntity

言い換えると:

// name mutator
Entity& Entity::name( const string& name ) {
    // [...] checks
    _name = name;
    return *this;
}

// budgetRange mutator
Client& Client::budgetRange( const long int& range ) {
    // [...] checks
    _budgetRange = range;
    return *this;   
}

それから私がそれを呼ぶとき:

Client a; a.name("UserName123").budgetRange(50);

コンパイラーは(論理的に)、EntityオブジェクトにはbudgetRangeメンバーがないと言います(nameはClientではなくEntityを返すため)。

今の私の質問は、どうすればこのようなものを実装できますか?子クラスのすべてのエンティティ関数をオーバーロードすることを考えましたが、それは良くなく、継承の考えに反するでしょう:)

よろしくお願いします:D

4

3 に答える 3

8

CRTPを使用する必要があります。

template<class Derived>
class Entity
{
    Derived* This() { return static_cast<Derived*>(this); }

public:
    Derived& name(const string& name)
    {
        ...
        return *This();
    }
};

class Client : public Entity<Client>
{
public:
    Client& budgetRange(const long& range)
    {
        ...    
        return *this;   
    }
};

仮想関数を使用する場合は、次のように抽象基本クラスを追加することもできます。

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

     virtual ~AbstractEntity();
};

template<class Derived>
class Entity : AbstractEntity
{...};
于 2011-12-20T13:17:00.713 に答える
3

ほぼすべてがすでに述べられているので、複数のレベルの継承でCRTPを使用できるようにする答えを追加したいと思います。

上記のCRTP実装は、 を参照するためClient、から継承したい場合に機能しなくなります。CRTPパターンを使用して、名前付きパラメーターのイディオムを複数レベルの継承で実行できるようにする場合は、次のようにクラスをコーディングする必要があります。DerivedClient

template<class Derived>
class Entity_T
{
protected:
    Derived* This() { return static_cast<Derived*>(this); }
public:
    Derived& name(const string& name)
    {
        ...
        return *This();
    }
};

template<class Derived>
class Client_T : public Entity_T<Derived>
{
    Derived& budgetRange(const long& range)
    {
        ...    
        return *This();   
    }
};

テンプレートのないバージョンのClient_Taddをユーザーに提供するには

class Client : public Client_T<Client> {};

これが拡大されたコードベースの価値があるかどうかは完全にあなた次第です。上記のコードをコンパイルしていないことに注意してください。

于 2011-12-20T13:57:07.427 に答える
3

「不思議なことに再帰的なテンプレート」パターンがここで役立つ可能性があります。次の行に沿って、基本クラスを派生クラスによってパラメーター化されたテンプレートにします。

template <typename Derived>
struct Entity {
    Derived & name(std::string const & name) {
        // stuff
        return static_cast<Derived&>(*this);
    }
};

struct Client : Entity<Client> {
    Client & budget(long range) {
        // stuff
        return *this;
    }
};

Client().name("Mike").budget(50); // should compile

これは、すべてのタイプがから直接継承する場合にのみ機能しますEntity。型をポリモーフィックにする必要がある場合(つまり、すべてが共通の基本クラスを共有する場合)、別の非テンプレート基本クラスを追加し、Entityそこから継承する必要があります。

于 2011-12-20T13:17:00.427 に答える