4

良い一日、

私が問い合わせているプロセスを 1 文で適切に説明する方法がわからないので、タイトルをお許しください。基本クラスやインターフェイスのユーザーが、オブジェクト自体や他のオブジェクトによってデフォルト以外の方法で認識されるデータを確実に割り当てる方法を探していました。だから私は次のことをしてきました:

struct ExampleInterface {
    virtual void SomeMethod() = 0;
    virtual std::string WhatLooksLikeAGetterButIsNot() = 0;
};

以下は実際の例です。

//So states can be "poped in and out".//
struct State
{
    //To retrive what the active state is called.//
    /*Code In Question--->*/virtual std::string RegardStateAs() = 0;/*<---Code In Question*/
    virtual void ExecuteState( VRGE::MDNode* metaData ) = 0;
};

アイデアは、最終的に A のようなことをすることです (このオプションにより、誰かが「更新」から派生した場合に発生を防止しようとする問題が可能になります):

struct Update : public State
{
    //Yadda yadda...//
    /*Code In Question--->*/std::string RegardStateAs() {
                                return std::string{ "Update" };
                            }/*<---Code In Question*/
};

B (このオプションでは、A が行うことはできません):

struct Update : public State
{
        //Yadda yadda...//
        //Not a good example, but the point gets across.//
        Update( std::string value ) {
            stateName = value;
        }
        /*Code In Question--->*/virtual std::string RegardStateAs() {
                                        return stateName;
                                 }/*<---Code In Question*/
            private: 
               std::string stateName;

};

私の質問は次のとおりです。これは良い習慣ですか、それとも悪い習慣ですか?

- - -編集 - - -:

これをコンパイルできるコンパイラにアクセスできませんが、この状況では「オーバーライド」が最適であると指摘されました。たとえば、次のようになります。

//So states can be "poped in and out".//
struct State
{
    //To retrive what the active state is called.//
    /*Code In Question--->*/virtual std::string RegardStateAs() = 0;/*<---Code In Question*/
    virtual void ExecuteState( VRGE::MDNode* metaData ) = 0;
};

struct Update : public State
{
    //Yadda yadda...//
    /*Code In Question--->*/std::string RegardStateAs() override {
                                return std::string{ "Update" };
                            }/*<---Code In Question*/
};
4

1 に答える 1

3

他の人が指摘したように、あなたの質問は実際には「オーバーロード」ではなく「オーバーライド」(ポリモーフィックな意味で) に対処しています。

State (静的) のすべてのサブクラスに固定ラベルが必要であると仮定すると、戦略は機能しますが、いくつかの制限があります。わかりやすくするために、「RegardAsState」を「ToString」と呼びます。ToString を基本クラス State のコンストラクターで呼び出す必要がある場合は、問題が発生します。これは、基本クラス コンストラクターの実行時に、Update などの派生クラスの ToString の v テーブル エントリがまだ確立されていないためです。State のデストラクタで ToString を呼び出す場合にも、同様の問題が存在します。

別の方法は、状態ラベルを基底クラス State の const std::string として単純に実装し、それを const std::string & public get アクセサー経由で返すことです。v-table の間接化を排除し、const ref による戻りを許可するという点で、少し効率的です。また、前述の State の ctor/dtor の問題を解消します。

上記の提案でさえ最適ではありません。ラベルがすべての個別の State サブクラスで同じである場合、これをインスタンス メソッドにする必要がないからです。風変わりなものにしたい場合は、ToString を静的 (ステートレス) アクセサーとして実装できます。これは、次のように定数文字列をテンプレート パラメーターとして渡すという、あまり知られていないトリックで実行できます。

template<const std::string & label>
struct State
{
    static const std::string & ToString()
    {
        return label;
    }
};

extern const std::string UpdateLabel = "Update";
State<UpdateLabel> Update;

// Or, with a bit of help from the macro preprocessor
#define DEFINE_STATE(stateClass) \
extern const std::string stateClass##Label = #stateClass; \
struct stateClass##State : State<stateClass##Label> \
// continue with definition of stateClass##State ... {}

DEFINE_STATE(Sample)
{
    // implementation of SampleState
};
于 2013-04-26T22:04:35.190 に答える