2012-03-22 18 views
1

クラスAが例えばIUnknownとIComSomething1を実装している場合、VTableのメソッドの順序は最初にIUnknownでIComSomething1よりも早くなることは知っています。私が知る限り、IComSomething1はIUnknownを継承するため、これは常に注文です。クラスが複数のインターフェイスを実装している場合、VTableのメソッドポインタの順序は何ですか?

しかし、クラスAがIUnknown、IComSomething1、IComSomething2を実装している場合はどうなりますか? IComSomething1とIComSomething2の間のVTableメソッドポインタの順序は何ですか?

(質問はCOMにのみ当てはまりませんが、vtableオフセットで関数を呼び出すというCOMの問題から出てきます)。

「そこに」いくつかの回答を見つけようとしましたが、まっすぐで明確な答えが見つかりませんでした。

ありがとうございます! :-)

+3

VC++の実装についての古い記事がありますが(http://www.openrce.org/articles/files/jangrayhood.pdf)、基本原則は変更されていないと思います実装は異なります)。 –

+1

なぜそれは重要ですか? vtablesは実装の詳細です。 C++標準にはvtableの概念はありません。 – fredoverflow

+1

@FredOverflow悲しいことに、COMオブジェクトインターフェイスはvtable実装にマップされます。それはおそらくCOMの質問として興味深いだけです。 –

答えて

4

クラス内のvtableメンバーの順序は明確に定義されていません。確かに、vtableポインタ間でデータメンバーを見つけることができます(そしてそうなります)。あなたはCOMを書いている場合は、あなたが前にあなたが結果を入れているポインタに書き込むには、あなたのQueryInterfaceに戻るには、好きなインターフェイスにキャストする必要があることは、のようなものです:。

HRESULT QueryInterface(REFIID riid, LPVOID *ppvObject) { 
    if (*riid == IID_MY_INTERFACE) { 
    *ppvObject = static_cast<IMyInterface *>(this); 
    return S_OK; 
    } else if (*riid == IID_SOMETHING_ELSE) { 
    *ppvObject = static_cast<ISomethingElse *>(this); 
    return S_OK; 
    } else /* ... */ 
} 

コンパイラあなたのためのインターフェイスのための右のオフセットを見つけるの世話をするでしょう。

それが実際にどのように動作するかについては、これが意味するものについて考える - の各インターフェイスは、オブジェクト内のオフセットのいくつかのサブレンジのオブジェクトとして存在している必要があります..あなたはこのようになりますクラスの階層構造があるだろう:

class IA { virtual void foo() = 0; int x;}; 
class IB { virtual void bar() = 0; int y; }; 
class C : public IA, public IB { int bar; }; 

あなたのメモリ内のレイアウトは、次のようになります。ここでは

00000000 vtable ptr for C 
00000004 vtable ptr for Ia 
00000008 int x 
0000000b vtable ptr for Ib 
00000010 int y 
00000014 int bar 

あなたは0x0000000bでクラスへのオフセット0x00000004を取得、またはIbによりIaのへのポインタを取得することができます。

ことが可能によるいくつかのケースではこれをさらに最適化することがあります。

00000000 vtable ptr for C and Ia 
00000004 int x 
00000008 vtable ptr for Ib 
0000000b int y 
00000010 int bar 

Iは、Win32のC++ ABIは実際にこれを行うかはわかりません。これを行うと、C vtableはIa vtableと同じメンバーで始まり、最後に余分なものが追加されます。

+1

中間最適化もあります。 'C' vtableは' Ia' vtableと共有されていますが、そこには2つのポインタがあります。これはABIとは独立して行うことができ、依然としてより良い参照の地域性を提供します。 – MSalters

+0

@MSalters、確かに、あなたは 'B' vtableも同様にマージすることができます。 – bdonlan

関連する問題