0

これに対する私の現在のアプローチが機能しない理由について、私の質問の技術的な部分に対して良い答えを得ました(derived**への代入base**はタイプセーフではありません。Derived** から Base** への変換および Derived* から Base* への変換も参照してください)。ただし、考えていることを C++ の方法で実装する方法については、まだよくわかりません。最後のタイトルが具体的すぎたので、新しい質問を開始します。

これはおそらく、私がやろうとしていることのより明確な説明です:

  1. 1 つのクラスから派生したクラスのすべてのインスタンスである多数のオブジェクトを作成します。
  2. これらのオブジェクトを、コンパイル時の人間が読み取れる識別子 (おそらく文字列?) と共に、ある種のマスター コンテナーに格納します。
  3. 他のコンポーネントから識別子のリストを取得し、マスター コンテナーを検索して、それらを対応するオブジェクトに (ポインター/参照として) 返し、読み取り/変更できるようにします。この時点で型安全性を破る必要があると思います。コンポーネントは、識別子によって要求している派生型を知っていると仮定します。

これは、マップ、ベクトル、およびオブジェクトへのポインターを使用するのに比較的単純でエレガントだと思いました (前の質問で単純化した例を示します) が、多くの C-スタイルの型キャストを使用して、コンポーネントがポインタを場所に渡してマスター コンテナからの値を格納できるようにします。これは、私が C++ パラダイムに従っていないことを示していますが、何を「すべき」でしょうか?

[編集] 以下は、私がこれをどのように想定したかについての架空のサンプル コードです。これが私の考えを明確にすることを願っています。

#include <map>
#include <vector>
#include <string>
using namespace std;

class BaseObj {};
class Der1Obj: public BaseObj {};
class Der2Obj: public BaseObj {};

typedef map<string, BaseObj**> ObjPtrDict;
typedef map<string, BaseObj*> ObjDict;

class BaseComp
{
public:
   ObjPtrDict objs;
};

class DervComp
{
   DervComp(){objs["d1"] = &d1; objs["d2"] = &d2; } // This wouldn't compile
   Der1Obj* d1;
   Der2Obj* d2;
}

typedef vector<BaseComp*> CompList;

void assign_objs(CompList comps, ObjDict objs)
{
   for (auto c = comps.begin(); c != comps.end(); c++)
     for (auto o = c.objs.begin(); o != c.objs.end(); o++)
       *(o->second) = objs[o->first];
}

int main(int argc, char* argv[])
{
    Der1Obj d, d1;
    Der2Obj d2;
    ObjDict objs;
    objs["d"] = &d;
    objs["d1"] = &d1;
    objs["d2"] = &d2;

    DervComp c;
    vector<DervComp*> comps;
    comps.push_back(&c);

    assign_objs(comps, objs); 

    return 0;
}
4

3 に答える 3

0

あなたが望むものを正しく手に入れたら、次のようにすることができます:

#include <vector>

class Base
{
public:
    enum eDerived
    {
    //name these whatever you like
        DER1,//for first derived class
        DER2,//for second derived class
        DER3//for third derived class
    };

    virtual eDerived type() = 0;//this will return the class type.
};

class Derived1: public Base
{
public:
    virtual eDerived type() { return DER1; }
};

class Derived2: public Base
{
public:
    virtual eDerived type() { return DER2; }
};

class Derived3: public Base
{
public:
    virtual eDerived type() { return DER3; }
};

int main()
{
    std::vector<Base*> myList;//container for all elements
    //You can store a pointer to any of the derived classes here like this:
    Base * a = new Derived1();
    Base * b = new Derived2();
    Base * c = new Derived3();

    myList.push_back(a);
    myList.push_back(b);
    myList.push_back(c);

    //Iterating through the container
    for( Base * tmp: myList)
    {
        //You can check the type of the item like this:
        if( tmp->type() == Base::DER1 )
        {  
            //and cast to a corresponding type.
            //In this case you are sure that you are casting to the right type, since
            //you've already checked it.
            Derived1 * pointerToDerived1 = static_cast<Derived1 *>(tmp);
        }
    }
}

任意のタイプのコンテナを選択できます。それらに ID を与えたい場合は、 を使用するかmap、クラス自体に追加することができます。

于 2012-07-12T12:03:49.930 に答える
0

あなたは、「それらを対応するオブジェクトに戻す」と言います。このために、なぜ base** を返したいのですか? 文字列からポインターへのマップを返すだけです。説明については、以下のコードを参照してください。

class Container
{
    void add(const string& aKey_in, Base* b)
    {
        myObjects[aKey_in] = b;
    }
    void getObjs(list<string> aKeys_in, map<string,Base*>& anObjMap_out)
    {
        for(all string s in the aKeys_in)
            anObjMap_out[s] = myObjects[s];
    }
private:
    map<string, base*> myObjects;
};

ここで条件が満たされます: 1 つのクラスから派生したクラスのすべてのインスタンスである多数のオブジェクトを作成します。 クラスを拡張して、作成ロジック、ファクトリ ロジックなどを含めることができます。

これらのオブジェクトを、コンパイル時の人間が読み取れる識別子 (おそらく文字列?) と共に、ある種のマスター コンテナーに格納します。 マップで達成

他のコンポーネントから識別子のリストを取得し、マスター コンテナーを検索して、それらを対応するオブジェクトに (ポインター/参照として) 返し、読み取り/変更できるようにします。この時点で型安全性を破る必要があると思います。コンポーネントは、識別子によって要求している派生型を知っていると仮定します。

ポインターへのポインターをクライアントに戻す必要はありません。オブジェクトポインタを返すだけです。

追記: 生のポインターの代わりに shared_ptr を使用してポインターを実装できます。クライアント コード (getObjs() メソッドを使用しているユーザー) が適切に記述されている場合、ベース ポインターから派生ポインターへの動的キャストは必要ありません。これらは、ベース ポインターを操作できる必要があります。とにかく、それはあなたがまだ尋ねていない別の質問です。

于 2012-07-12T12:21:54.460 に答える
0

あなたの他の投稿を読みましたが、なぜ二重ポインタを使用するのか理解できないと思います。私の理解では、通常のポインターを使用するだけです。

例えば

class Base
{
};

class Deriv : public Base
{
};

std::map< std::string, Base* > ObjectStore;

function Component1( ... )
{
   Base* b = ObjectStore[ "MyObject" ];
   b->DoSomeFancyStuff();
}

function ModifyObjectStore( )
{
   delete ObjectStore[ "MyObject" ];
   ObjectStore[ "MyObject" ] = new Derived(); 

}

これが役立つことを願っています。

于 2012-07-12T12:12:15.007 に答える