0

基本クラスのペアがあるとします。

class A
{};

class B
{
    virtual void foo(A* ref);
    virtual void foo2(A* ref);
};

そして、それらから、いくつかの派生クラス:

class C : virtual public A
{
   int data;
};

class D : public B
{
    virtual void foo(A* ref)
    {
        ((C*) (ref)).data = 5;
    }
};

class E : virtual public A
{
    int otherData;
};

class F : public B
{
    virtual void foo2(A* ref)
    {
        ((E*) (ref)).otherData = 6;
    }
};

そして最後に、それに続くクラスがあります。

class G : public E, public C
{
};

次のような main 関数を使用します。

int main()
{
   B* myD = new D();
   B* myF = new F();

   A* myA = new G();

   myD->foo(myA);
   myF->foo2(myA);

   return 0;
}

わかりました、これが「恐ろしいダイヤモンド」であるという明白な事実を無視します (これにより、「複数の As」の問題は回避されましたvirtual)。一般的な考え方は、すべてのオブジェクトを G、D、および F にしたいということですが、 As および Bs への参照として格納されます。B の (実際には常に D または F のいずれかである) 仮想関数を使用して G の値を変更できるようにしたいのですが、A と B は子クラスを認識していないため、使用して宣言することはできません。彼ら。これは、仮想関数の引数が常に A へのポインターでなければならないことを意味します。ただし、D は入力が常に C であることを望んでおり、F は入力が E であることを望んでいます。G が1 つの親からのみ継承し、現在の G は 2 つの親から継承しています。方法がわからないthisポインターは、実際にはこのような状況の根底にあるコンテキストで機能します...しかし、これが可能な状況になるとは思いません。

親/子クラスへのポインターをキャストするメカニズムに光を当てることをいとわない人はいますか?また、これを実現する方法があれば?

4

3 に答える 3

1

RTTIがオンになっていると仮定すると、これはおそらくそうですが、dynamic_castを使用して、基本クラスポインターを派生(または兄弟)クラスポインターにアップキャストしようとすることができます。参照されるオブジェクトは実行時にテストされ、互換性のあるクラスであるかどうかが確認されます。これが有効なアップキャストでない場合は、0が返されます。この場合、オブジェクトをテストして分岐できます。

http://en.wikipedia.org/wiki/Dynamic_cast

于 2012-06-08T07:00:02.940 に答える
1

Aはの仮想ベースであるため、へのポインタを静的へのGポインタに変換することはできません。の全体的な意味は「実行時に決定される」ため、ポインタを持つサブオブジェクトの性質は実行時にのみ知ることができます。たとえば、あなたの場合、次のことを考慮してください。AGvirtualA

A * p = new G, q = new C;

ここで、pとはいくつかのqサブオブジェクトを指しますが、それらが含まれている最も派生したオブジェクトの性質は、実際の最も派生したタイプによってのみ決定されます。したがって、からまたはへの単一の固定変換ルールを持つことは不可能です。 AA*G*A*C*

キャストを実行する唯一の方法は動的に、つまり経由dynamic_cast<C*>(p)などです。

(対照的に、非仮想継承では、サブオブジェクトがより派生したオブジェクトとどのように関連するかが常にわかっているため、ポインターを静的に変換できます。複数の繰り返しベースがある場合、名前のあいまいさの問題が発生する可能性がありますが、問題はありません。ベースサブオブジェクトを検索します。)

于 2012-06-08T07:47:37.607 に答える
0

KerrekとAndrewが言うように、を使用する必要がありますdynamic_cast。ただし、の子Aが静的である場合は、別のトリックを使用できます。これは、より高速である可能性がありますdynamic_cast(RTTIに依存しないため、詳細については、この質問を参照してください)。

class C;
class D;
class E;
class F;

class A
{
public:
    virtual C * isC () { return 0; }
    virtual E * isE () { return 0; }
};

class C : virtual public A
{
    friend class D;
    int data;
    C * isC () { return this; }
};

class E : virtual public A
{
    friend class F;
    int otherData;
    E * isE () { return this; }
};

これで、有効なポインタを返すかどうかを確認するためにクエリを実行できますDFAisCisE

于 2012-06-08T09:41:27.713 に答える