上記のタイトルに示されているように、私の質問は単純に、C++ キャストがターゲット クラスの新しいオブジェクトを作成するかどうかです。もちろん、これを質問する前に Google、MSDN、IBM、stackoverflow の検索ツールを使用しましたが、質問に対する適切な回答が見つかりません。
仮想継承を使用して解決されたダイヤモンド問題の次の実装を考えてみましょう。
#include <iostream>
#include <cstdlib>
struct A
{
int a;
A(): a(2) { }
};
struct B: virtual public A
{
int b;
B(): b(7) { }
};
struct C: virtual public A
{
int c;
C(): c(1) { }
};
struct END: virtual public B, virtual public C
{
int end;
END(): end(8) { }
};
int main()
{
END *end = new END();
A *a = dynamic_cast<A*>(end);
B *b = dynamic_cast<B*>(end);
C *c = dynamic_cast<C*>(end);
std::cout << "Values of a:\na->a: " << a->a << "\n\n";
std::cout << "Values of b:\nb->a: " << b->a << "\nb->b: " << b->b << "\n\n";
std::cout << "Values of c:\nc->a: " << c->a << "\nc->c: " << c->c << "\n\n";
std::cout << "Handle of end: " << end << "\n";
std::cout << "Handle of a: " << a << "\n";
std::cout << "Handle of b: " << b << "\n";
std::cout << "Handle of c: " << c << "\n\n";
system("PAUSE");
return 0;
}
私が理解したように、B と C の実際の構造は、通常、A の埋め込みインスタンスと B の変数の両方で構成されています。あいまいさを避けるために、B と C の仮想 A が END の 1 つの埋め込みオブジェクトにマージされるため、C は破棄されます。(私がいつも思っていたように)dynamic_castは通常、ポインターによって格納されたアドレスを、埋め込まれた(キャストの)ターゲットクラスのオフセットだけ増加させるだけなので、ターゲット(BまたはC)クラスがいくつかに分割されているという事実のために問題が発生します部品。
しかし、MSVC++ 2011 Express で例を実行すると、すべてが期待どおりに実行されます (つまり、すべて *.a 出力 2 で実行されます)。ポインターはわずかに異なるだけです。したがって、キャストはソースポインターのアドレスを B の / C のインスタンスの内部オフセットだけ移動するだけだと思います。
しかし、どのように?B / C の結果のインスタンスは、共有された A オブジェクトの位置をどのように認識しますか。END オブジェクト内には A オブジェクトが 1 つしかありませんが、通常は B と C に A オブジェクトがあるため、B または C のいずれかに A のインスタンスがあってはなりませんが、実際には両方にインスタンスがあるように見えます。
またはvirtual
、A から virtual を継承する各基本クラスのそれぞれの A オブジェクトを削除せずに、A のメンバーへの呼び出しのみを中央の A オブジェクトに委譲します (つまりvirtual
、実際には、継承されたオブジェクトと埋め込まれたオブジェクトの内部構造を破壊せず、仮想化されたオブジェクトを使用しないだけです ( = 共有) メンバー)?
またはvirtual
、そのようなキャストされたオブジェクトが「分散」を処理するために、新しい「オフセットマップ」(つまり、クラスインスタンスへのポインターに関連するすべてのメンバーのアドレスオフセットを示すマップ、実際の用語はわかりません) を作成しますか?
すべてを明確にしたことを願っています。事前に感謝します
BlueBlobb
PS:
文法の間違いがありましたら申し訳ありません。私はビールが大好きなバイエルン人であり、ネイティブ スピーカーではありません :P
編集:
すべての int a のアドレスを出力するためにこれらの行を追加した場合:
std::cout << "Handle of end.a: " << &end->a << "\n";
std::cout << "Handle of a.a: " << &a->a << "\n";
std::cout << "Handle of a.b: " << &b->a << "\n";
std::cout << "Handle of a.c: " << &c->a << "\n\n";
それらは同じであり、実際には A オブジェクトが 1 つしかないことを意味します。