趣味C,C++プログラマ7年目、VC++使用2年目です。
ATLのヘッダを覗いていたら題名のキーワードが出てきましたが
MSDNやgoogleで調べても理解できませんでした。
試しに下記のようなコードを書いて実験してみました。
//////////////////////////////////////////////////////////////////////
class __declspec(novtable) X
{
public:
virtual void func() = 0;
};
class A : public X
{
public:
void func() { printf(A::func()\n); };
};
int main(int argc, char* argv[])
{
A a;
A* pa = new A;
a.func();
pa->func();
delete pa;
return 0;
}
//////// 実行結果 /////////////
A::func()
A::func()
//////////////////////////////////////////////////////////////////////
最初はnovtableという名前から仮想関数テーブルが生成されないと思い
上記のpa->func()はアクセス違反が起きると思ったのですが
実行した結果問題ないように見えました。(メモリ上も同じvtableを指していました)
次に、MSDNに
>クラスのコンストラクタおよびデストラクタに vfptr の初期化用コードが生成されません。
と書いてあったのでインスタンスの生成方法が違うのかなと思い
少々アセンブラの知識があるのでデバッガで追ってみたところ
novtavleをつける場合ではクラスXのコンストラクタでvtableのアドレスを設定していないこと
がわかりました。
novtableの効果はわかったのですが、結局何に使うんだ?という疑問がわきました。
novtableを付けても付けなくてもメンバ関数呼び出しに問題はなさそうですし
実際どういう場面で使用するかわかりません。
なにかデメリットがあるんでしょうか?
忘れてました.
VC++6.0 SDKです。
このキーワードは始めてみました。
MSDNを調べてみたところ、同じ質問と答えがありました。
「ATL Virtual Functions and vtables」
http://msdn.microsoft.com/msdnmag/issues/0300/c/default.aspx
novtableを指定しない場合、Xのコンストラクタでは、
クラスX用のvtableの初期化が行われます。
これは、仮想関数の場合であっても省略されず、
vtableをNULLクリアするコードが生成されます。
そして、AのコンストラクタではX::X()を呼び出した後、
クラスA用のvtableの初期化が行われます。
__declspec(novtable)をつけることによって、
この用の無い初期化を省略することが目的のようです。
普通は、NULLで初期化する程度のコードについて
気にする必要はないでしょうが、
ATLでCOMクラスを作る場合、たくさんの抽象クラスを
継承するので、比較的小さいクラスオブジェクトを作る場合に
このNULL代入のオーバーヘッドが馬鹿にならないため、
__declspec(novtable)を付けているようです。
ネットの方のMSDN調べてませんでした。
リンク先はまさに私が求めていた答えでした。
一種の最適化みたいなものなのですね。
ありがとうございました。