残念ながら、LuchianGrigoreの答えは正しくありません。
ダイヤモンド継承の場合は正しいでしょう。Bから継承するクラスDとAから継承するCがある場合。Dの関数を呼び出すと、D参照を検索するための追加操作がvtableにあります。
(e.g) in Memory
------- Classes hierarchy
---> | A | A
the offset here | ------- / \
is the pointer -> | | ... | B C <- Diamond Inheritance
addition he is | ------- \ / (usually very bad)
talking about ---> | D | D
-------
あなたの場合、ポリモーフィック呼び出しの場合、コンパイラは、呼び出している適切な関数を取得するために、vtableでルックアップ(読み取り)を実行する必要があります。さらに悪化するのは、vtableが指しているデータがキャッシュされていない場合です。その場合、キャッシュミスが発生しますが、これは非常にコストがかかります。
さらに、クラスごとに1つのvtableがあり、そのクラスの各オブジェクトは同じvtableを共有します。C ++では、vtableとは何ですか?どのように機能しますか?を参照してください。
あなたの質問に対する本当の答えは、それらの30のクラスすべての間で何回交換するか、そしてどれくらいの頻度でそれらを使用するかによって異なります。ループで使用されますか?
あなたが説明している解決策は、この潜在的な問題を回避するためによく使用されます。ただし、実際には、使用方法によっては、ポリモーフィック呼び出しと同じくらい高速になる場合があります。
したがって、一般的には、無視できるため、コストを気にせずにポリモーフィックメソッドを使用できます。最初にクリーンで保守可能なコードを記述し、後で最適化します。:)
編集 :
このスレッドで実際のコンパイラコードについての議論があったので、実際に何が起こっているのかを調べるためにサンプルを実行することにしました。
以下に、私が使用したコードのサンプルを示します。
#include <stdlib.h>
#include <stdio.h>
class I
{
public:
virtual void f(void) = 0;
};
class A : public I
{
public:
void f(void)
{
printf("A\n");
}
};
int main(int argc, char* argv[])
{
__asm
{
int 3
}
A* pA = new A();
__asm
{
nop
nop
}
pA->f();
__asm
{
nop
nop
}
A a;
a.f();
__asm
{
nop
nop
}
return 0;
}
次に、サンプルの実際のアセンブリコード(コンパイラがどのように解釈したか)を確認できます。
int main(int argc, char* argv[])
{
__asm
{
int 3
010E1010 int 3
}
A* pA = new A();
010E1011 push 4
010E1013 call operator new (10E10A4h)
010E1018 add esp,4
010E101B test eax,eax
010E101D je main+17h (10E1027h)
010E101F mov dword ptr [eax],offset A::`vftable' (10E2104h)
010E1025 jmp main+19h (10E1029h)
010E1027 xor eax,eax
__asm
{
nop
010E1029 nop
nop
010E102A nop
}
pA->f();
010E102B mov edx,dword ptr [eax]
010E102D mov ecx,eax
010E102F mov eax,dword ptr [edx]
010E1031 call eax
__asm
{
nop
010E1033 nop
nop
010E1034 nop
}
A a;
a.f(); //Polymorphic call
010E1035 push offset string "A\n" (10E20FCh)
010E103A call dword ptr [__imp__printf (10E20ACh)]
010E1040 add esp,4
__asm
{
nop
010E1043 nop
nop
010E1044 nop
}
return 0;
010E1045 xor eax,eax
}
class A : public I
{
public:
void f(void)
{
printf("A\n");
010E1000 push offset string "A\n" (10E20FCh)
010E1005 call dword ptr [__imp__printf (10E20ACh)]
010E100B pop ecx
}