1
#include <iostream>
using namespace std;

class Base {
public:
    Base() {
        cout << "In Base" << endl;
        cout << "Virtual Pointer = " << (int*)this << endl;
        cout << "Address of Vtable = "
        << (int*)*(int*)this << endl;
        cout << "Value at Vtable = "
        << (int*)*(int*)*(int*)this << endl;
        cout << endl;
    }

    virtual void f1() { cout << "Base::f1" << endl; }
};

class Drive : public Base {
public:
    Drive() {
        cout << "In Drive" << endl;
        cout << "Virtual Pointer = "
        << (int*)this << endl;
        cout << "Address of Vtable = "
        << (int*)*(int*)this << endl;
        cout << "Value at Vtable = "
        << (int*)*(int*)*(int*)this << endl;
        cout << endl;
    }

    virtual void f1() { cout << "Drive::f2" << endl; }
};

int main() {
Drive d;
return 0;

}

このプログラムの出力は

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C08C
Value at Vtable = 004010F0

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C07C
Value at Vtable = 00401217

コードに従ってください。Drive オブジェクトを作成すると、Base コンストラクターも実行され、Drive の仮想ポインターと同じ仮想ポインターのアドレスが表示されることがわかります: 0012FF7C。奇妙なことに、Base クラスと Drive クラスの両方のコンストラクターでそのアドレスを逆参照すると、異なる値が指され、1 つは 0046C08C に、もう 1 つは 0046C07C に 2 つの vtable があることを意味します。Drive オブジェクトの構造と、1 つのポインターが 2 つのアドレスを指している場合の言語を理解するのは非常に困難です。

4

2 に答える 2

5

オブジェクトの構築は段階的に行われます。最初のステップは基本クラスを初期化することです。そのプロセスの間、オブジェクト基本オブジェクトになります。vtable は基本クラスのメソッドを反映します。構築が派生クラスに進むと、vtable は派生クラスの vtable になるように更新されます。

これはすべて C++ 標準によって規定されていますが、もちろん標準では vtable の実装が義務付けられていません。

于 2012-06-05T04:12:23.070 に答える
3

C++コンパイラがC++標準で設定されたルールをどのように実装するかを目撃しました。Baseコンストラクターの実行中、仮想メソッドの呼び出しは、オーバーライドするBase場合でも、実装にディスパッチする必要があります。Driveこれを実現するために、C++コンパイラは明らかにオブジェクトのvtableポインタがvtableを指すようにしますBase。コンストラクターが終了し、Baseコンストラクターで実行が続行されるDriveと、vtableポインターが更新されてvtableを指すようになりDriveます。

それはそれを実装するための便利な方法になります。コンパイラが仮想メソッドを呼び出すための命令を生成する残りのコードは、特別なコンストラクターの動作が必要かどうかを検出するために変更する必要はありません。いつものようにvtableを見ることができます。vtableポインターを変更すると、コンストラクターの実行中にオブジェクトの有効な実行時型をすばやく変更できます。

デストラクタは同じように機能しますが、逆に機能することがわかります。Baseオブジェクトの代わりにオブジェクトを作成する場合は、オブジェクトのコンストラクターでDrive表示するのと同様のアドレスが表示される可能性があります。BaseDrive

于 2012-06-05T04:17:07.670 に答える