6

VTable に関する多くのリソースがオンラインにあります。彼らは一般的にそれらに関して同じ声明を持っています:

"クラス自体が仮想関数を含むか、親クラスの仮想関数をオーバーライドするときはいつでも、コンパイラはそのクラスの vtable を作成します。これは、すべてのクラスがコンパイラによって作成された vtable を持っているわけではないことを意味します。vtable には、そのクラスの仮想関数。クラスごとに 1 つの vtable しか存在できず、同じクラスのすべてのオブジェクトが同じ vtable を共有します。 "

では、なぜこれは、すべてのクラスがコンパイラによって作成された vtable を持っているわけではないことを意味するのでしょうか? somc クラスに仮想関数がないからですか?

4

3 に答える 3

7

正確に。一部のクラスには仮想メソッドがないため、vtable がありません。

仮想メソッドは、クラスの実装によって異なるため、コンパイラが直接呼び出しを生成できないメソッドです。Vtable は一種のルックアップ テーブルで、プログラムの実行時にどの実装を呼び出すかの決定を遅らせることで、この問題を解決します。関数呼び出しを生成する代わりに、コンパイラは vtable でメソッド ルックアップを生成し、返されたメソッドを呼び出します。 .

次の例を見てください。

class Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Foo::vMethod was called!" << std::endl;
    }
};

class Bar : public Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Bar::vMethod was called!" << std::endl;
        std::cout << "This is not the same as Foo::vMethod." << std::endl;
    }
};

Foo* foo = new Bar;
foo->vMethod();

これにより、Barのメッセージが出力されます。ほとんどの重要なシナリオでは、コンパイラは、仮想メソッドが呼び出されるオブジェクトの型を事前に知ることができません。前述のように、vtable は、オブジェクトのタイプに関係なく、メソッドの実装を見つけるための統一されたルックアップ メカニズムを提供することで問題を解決します。

vtable ポインターは、クラスのすべてのインスタンスに存在する必要があります (これには、追加のメモリのポインターのサイズが必要です。おそらく 4 または 8 バイトです)。これは大したことではないように思えるかもしれませんが (実際、多くの人が同意するでしょう)、これは特定のシナリオ (メモリが非常に限られている組み込みシステムなど) では扱いにくい場合があります。クラスごとに vtable を用意すると、使用した分だけ料金を支払うという一般的な C++ の原則に違反するため、必要がなければコンパイラは vtable を生成しません。

vtableがない場合実行時の型情報が無効になるという顕著な副作用があります。コードでRTTIを使用する必要がある場合、クラスには少なくとも 1 つの仮想メソッドが必要です。このような場合、デストラクタを virtual とマークするのが慣習です。

于 2011-04-18T23:13:10.167 に答える
5

実際、C++ では、どのクラスにも vtable があることを必要とするものはありません。これは完全に実装上の問題です。ただし、仮想関数を持つクラスは何らかの形でポリモーフィック関数呼び出しをサポートする必要があり、これには常に何らかのテーブル/マップが必要です。このテーブル/マップは、ポリモーフィック関数を持つクラス用にコンパイラによって作成され、(コンパイラの品質に応じて) そうでないクラス用に作成される場合があります。

于 2011-04-18T23:16:09.887 に答える
2

さらに、明示的に削除されているため、一部のクラスには vtable がありません。__declspec(novtable)(コンパイラ固有)を参照してください。

于 2011-04-19T00:19:32.023 に答える