10

更新: デストラクタの例を単純なメソッド呼び出しの例に置き換えました。

やあ、

次のコードがある場合:

class a
{
public:
    virtual void func0(); // a has a VTable now
    void func1();
};
class b : public a
{
public:
    void func0() { a::func0(); }
    void func2();
};
  1. B に VTable はありますか? B には仮想関数はありませんが、b::func0() から a::func0() を呼び出します
  2. func1 は VTable に存在しますか? 仮想ではありません。
  3. func2 は VTable に存在しますか?
  4. aa::func0() 呼び出しが b::func0() にない場合、上記の答えは異なりますか?

ありがとう

4

4 に答える 4

19

仮想関数を宣言する場合は、デストラクタを仮想として宣言する必要があります ;-)。

  1. B には仮想関数、つまり があるため、仮想テーブルがありますfunc0()。関数 (デストラクタを含む) virtual を基底クラスで宣言すると、そのすべての派生クラスにも同じ署名 virtual を持つ関数が含まれます。そして、それはそれらにvtableを持たせます。func0さらに、明示的に宣言していなくても、B には vtable があります。

  2. 非仮想関数は、vtable を通じて参照されません。

  3. 2を参照してください。

  4. いいえ。クラスの vtable は、クラス宣言に基づいて構築されます。クラスの関数の本体 (他の関数は言うまでもなく) は考慮されません。func0()したがって、B の機能は仮想であるため、B には vtableがあります。

それはあなたの質問の要点ではありませんが、トリッキーな詳細もあります。B::func0()関数をインラインとして宣言しました。コンパイラではgcc、仮想関数がインラインで宣言されている場合、そのスロットは仮想テーブルに保持されます。スロットは、そのインライン関数に対して発行された特別な関数を指します (そのアドレスを取得すると見なされ、インラインが発行されます)。つまり、関数がインラインであるかどうかは、vtable のスロットの量とクラスの必要性に影響しません。

于 2009-09-05T16:04:57.187 に答える
5
  1. はい、その基本クラスには 1 つあるためです。また、基本クラスのデストラクタが仮想であるため、そのデストラクタも仮想です (仮想と宣言していませんが)。

  2. いいえ

  3. いいえ。

  4. いいえ。実際には、現在のコードが正当であるとは思いません。~B から ~A を明示的に呼び出さなくても、コンパイラは B デストラクタを呼び出した後に A デストラクタを呼び出します。したがって、コンパイラで許可されていても、~B から ~A を呼び出す必要はないと思います。

于 2009-09-05T16:01:26.243 に答える
3

更新された例を参照すると、次のようになります。

  1. はい、bには vtable があります。b::func0() は仮想 (a::func0() をオーバーライド) であることに注意してください。ただし、明示的に仮想としてラベル付けしていません。奇妙な C++ の「抜け穴」だと思います。
  2. いいえ。非仮想関数は vtable には存在しません。
  3. 2を参照してください。
  4. いいえ。 a:func0(); をオーバーライドしました。a::func0() を呼び出すかどうかは問題ではありません。

いくつかの追加のメモ (コンパイラに依存しますが、これらはかなり一般的な一般化です):

  • 仮想関数を持つクラスから派生しているため、bのすべてのインスタンスには vtable へのポインターがあります。
  • これは、b::func0() を定義していなくても当てはまります
  • この状況では、コンパイラはbのインスタンスがaの静的 vtableを指すようにするか、 bの静的 vtable を作成し、aのメンバーへのポインターへのポインターで埋めます。
  • ただし、 aへのポインターを介してbのインスタンスに適切にアクセスできるようにするためには、依然として必要です
于 2009-09-05T17:00:45.273 に答える
1
  • 基本クラス関数が仮想の場合、派生クラスでその関数をオーバーライドすると、明示的に指定しなくても暗黙的に仮想になります。クラスに仮想関数がある場合は、av テーブルがあります。
  • vtable に存在する仮想関数のみ、function1 は vtable に存在しません
  • function2 は上記と同じ理由で vtable に存在しません
  • vtable の作成は、その関数を基底クラスから呼び出すか、他の場所から呼び出すかに依存しません。関数呼び出しは、vtable の作成を決定しません。
于 2009-09-05T17:55:32.963 に答える