ディレクトリ
1.仮想関数リストの位置
2.リスト仮想関数の内容
コンテンツのチェーンを継承した仮想関数の3 Aリスト
注意:
仮想関数テーブルも、それへのポインタがvptrと呼ばれ、仮想、VTBLと呼ばれるvs2019が__vfptrと呼ばリスト
オペレーティングシステム:Windows 10 Professionalの64ビット
コンパイラ:Visual Studioの2019コミュニティ
1.仮想関数リストの位置
結論
コンパイラは仮想関数リスト・オブジェクト・インスタンスへのポインタポイントの一般的な位置が最前面に存在することを確実にします
そして、関数ポインタ、複数の仮想関数リストの内容
コードの検証:
まず、ベースクラス宣言Base
と派生クラスをDerived
class Base
{
public:
virtual void f() { std::cout << "Base1::f" << std::endl; }
virtual void g() { std::cout << "Base1::g" << std::endl; }
virtual void h() { std::cout << "Base1::h" << std::endl; }
virtual void i() { std::cout << "Base1::i" << std::endl; }
};
class Derived : public Base
{
virtual void g() override { std::cout << "Derived::g" << std::endl; }
virtual void h1() { std::cout << "Derived::i1" << std::endl; }
};
次に、派生クラスのオブジェクトをインスタンス化します
Derived derived;
今、私たちはオブジェクトのアドレスをプリントアウト
std::cout << "derived对象的地址: " << (&derived) << std::endl;
我々は仮定しているので指向虚函数列表的<指针>存在于对象实例中最前面的位置
我々はそれを取ることができるようderived对象的地址
に先頭に指针
アドレス(ポインタPaと呼ばれます)
そして、関数ポインタ(PFと呼ばれるポインタ)である仮想関数リストの先頭に、このポインタ(PA)
したがって、ポインタ(PA)、指向指针的指针
ポインタ(PA)の、即ち、ポインタ(PF)
この推測に基づいて、我々はなりますderived对象的地址
つまり指针pA的地址
型変換可能
使用しreinterpret_cast<int**>
たキーワードは、Aに変換します指向指针的指针
reinterpret_cast<int**>(&derived)
我々は今、コンテンツの方ポインタ(PA)を、対処、コンテンツは、PAを取得します
std::cout << "derived对象中第一个指针的内容: " << *reinterpret_cast<int**>(&derived) << std::endl;
上記の憶測によると、コンテンツは仮想関数リストのアドレスです
次のようにコンソール出力は次のようになります。
vs2019することで、あなたはに直接見ることができるderived
オブジェクト、コンテンツ__vfptrアドレスと印刷が同じコンソールです
継承されたコンテンツのリストにある2つの仮想関数
基本クラスは、すなわち、4つの機能を持っています
f();
g();
h();
i();
派生クラス、すなわち、2つの機能を有します
g();
i1();
これでフォームがオーバーライドの機能を、簡単に鑑賞するための方法を表した使用、それは同じライン上に配置されます
結論仮想関数リスト、下に示すように、関数のレイアウト。
コードの検証を参照してください。链式继承中虚函数列表的内容
コンテンツのチェーンを継承した仮想関数の3 Aリスト
三つのカテゴリー声明、継承がされてDerived
継承されBase2
、Base2
継承Base1
class Base1 {
public:
virtual void f() { std::cout << "Base1::f" << std::endl; }
virtual void g() { std::cout << "Base1::g" << std::endl; }
virtual void h() { std::cout << "Base1::h" << std::endl; }
virtual void i() { std::cout << "Base1::i" << std::endl; }
};
class Base2 : public Base1{
public:
virtual void f()override { std::cout << "Base2::f" << std::endl; }
virtual void h1() { std::cout << "Base2::h1" << std::endl; }
};
class Derived : public Base2 {
public:
virtual void g()override { std::cout << "Derived::g" << std::endl; }
virtual void i1() { std::cout << "Derived::i1" << std::endl; }
};
メソッドの形で表されます。
结论
在虚函数列表中, 函数的布局如下图所示:
Derive只有一个虚函数表, 是在Base2的虚函数表上, 进行类似于单继承的覆盖
同理, Base2也有一张虚函数表, 是在Base1的虚函数表上, 进行单继承的覆盖
代码验证
////////////////////////////////////////////////////////////////////////////////
// 链式继承
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
class Base1 {
public:
virtual void f() { std::cout << "Base1::f" << std::endl; }
virtual void g() { std::cout << "Base1::g" << std::endl; }
virtual void h() { std::cout << "Base1::h" << std::endl; }
virtual void i() { std::cout << "Base1::i" << std::endl; }
};
class Base2 : public Base1{
public:
virtual void f()override { std::cout << "Base2::f" << std::endl; }
virtual void h1() { std::cout << "Base2::h1" << std::endl; }
};
class Derived : public Base2 {
public:
virtual void g()override { std::cout << "Derived::g" << std::endl; }
virtual void i1() { std::cout << "Derived::i1" << std::endl; }
};
using Fun = void(*)(void);
int main()
{
Fun pFun = nullptr;
// 操作系统: windows 10 专业版 32/64位都可以
// 编译器 : Visual Studio 2019 Community
std::cout << sizeof(int) << std::endl; // 32位:4 64位:4
std::cout << sizeof(long) << std::endl; // 32位:4 64位:4
std::cout << sizeof(int*) << std::endl; // 32位:4 64位:8
std::cout << "-------------------------------------------------------------------------------------- " << std::endl;
std::cout << "Base1的虚表如下 " << std::endl;
Base1 base1;
std::cout << "base1对象的地址: " << (&base1) << std::endl;
std::cout << "base1对象中第一个指针的地址(不是内容): " << (&base1) << std::endl;
// &base1 是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个虚表(虚表的内容也是一堆指针)
std::cout << "base1对象中第一个指针的内容: " << *reinterpret_cast<int**>(&base1) << std::endl;
std::cout << "base1虚函数表地址: " << *reinterpret_cast<int**>(&base1) << std::endl;
// 虚函数表地址, 也是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个函数指针
std::cout << "base1虚函数表 — 第一个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1))))) << std::endl;
pFun = reinterpret_cast<Fun>(* (reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)))));
std::cout << "base1虚函数表 — 第一个函数内容:";
pFun(); // base1::f
std::cout << std::endl;
// 注意次数的偏移量, 32位偏移量是+1, 64位偏移量是+2
std::cout << "base1虚函数表 — 第二个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1))+1*(sizeof(int*)/sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)) + 1 * (sizeof(int*) / sizeof(int)))));
std::cout << "base1虚函数表 — 第二个函数内容:";
pFun(); // base1::g
std::cout << std::endl;
std::cout << "base1虚函数表 — 第三个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)) + 2 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)) + 2 * (sizeof(int*) / sizeof(int)))));
std::cout << "base1虚函数表 — 第三个函数内容:";
pFun(); // base1::h
std::cout << std::endl;
std::cout << "base1虚函数表 — 第四个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)) + 3 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base1)) + 3 * (sizeof(int*) / sizeof(int)))));
std::cout << "base1虚函数表 — 第四个函数内容:";
pFun(); // base1::i
std::cout << std::endl;
std::cout << "-------------------------------------------------------------------------------------- " << std::endl;
std::cout << "Base2的虚表如下 " << std::endl;
Base2 base2;
std::cout << "base2对象的地址: " << (&base2) << std::endl;
std::cout << "base2对象中第一个指针的地址(不是内容): " << (&base2) << std::endl;
// &base1 是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个虚表(虚表的内容也是一堆指针)
std::cout << "base2对象中第一个指针的内容: " << *reinterpret_cast<int**>(&base2) << std::endl;
std::cout << "base2虚函数表地址: " << *reinterpret_cast<int**>(&base2) << std::endl;
// 虚函数表地址, 也是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个函数指针
std::cout << "base2虚函数表 — 第一个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)))));
std::cout << "base2虚函数表 — 第一个函数内容:";
pFun(); // base2::f
std::cout << std::endl;
std::cout << "base2虚函数表 — 第二个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 1 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 1 * (sizeof(int*) / sizeof(int)))));
std::cout << "base2虚函数表 — 第二个函数内容:";
pFun(); // base1::g
std::cout << std::endl;
std::cout << "base2虚函数表 — 第三个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 2 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 2 * (sizeof(int*) / sizeof(int)))));
std::cout << "base2虚函数表 — 第三个函数内容:";
pFun(); // base1::h
std::cout << std::endl;
std::cout << "base2虚函数表 — 第四个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 3 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 3 * (sizeof(int*) / sizeof(int)))));
std::cout << "base2虚函数表 — 第四个函数内容:";
pFun(); // base1::i
std::cout << std::endl;
std::cout << "base2虚函数表 — 第五个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 4 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&base2)) + 4 * (sizeof(int*) / sizeof(int)))));
std::cout << "base2虚函数表 — 第五个函数内容:";
pFun(); // base2::h1
std::cout << std::endl;
std::cout << "-------------------------------------------------------------------------------------- " << std::endl;
std::cout << "Derived的虚表如下 " << std::endl;
Derived Derived;
std::cout << "Derived对象的地址: " << (&Derived) << std::endl;
std::cout << "Derived对象中第一个指针的地址(不是内容): " << (&Derived) << std::endl;
// &base1 是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个虚表(虚表的内容也是一堆指针)
std::cout << "Derived对象中第一个指针的内容: " << *reinterpret_cast<int**>(&Derived) << std::endl;
std::cout << "Derived虚函数表地址: " << *reinterpret_cast<int**>(&Derived) << std::endl;
// 虚函数表地址, 也是一个指向指针的指针
// 对它进行*操作, 得到了这个指针的内容, 即它指向的位置, 是一个函数指针
std::cout << "Derived虚函数表 — 第一个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)))));
std::cout << "Derived虚函数表 — 第一个函数内容:";
pFun(); // base2::f
std::cout << std::endl;
std::cout << "Derived虚函数表 — 第二个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 1 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 1 * (sizeof(int*) / sizeof(int)))));
std::cout << "Derived虚函数表 — 第二个函数内容:";
pFun(); // Derived::g
std::cout << std::endl;
std::cout << "Derived虚函数表 — 第三个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 2 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 2 * (sizeof(int*) / sizeof(int)))));
std::cout << "Derived虚函数表 — 第三个函数内容:";
pFun(); // base1::h
std::cout << std::endl;
std::cout << "Derived虚函数表 — 第四个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 3 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 3 * (sizeof(int*) / sizeof(int)))));
std::cout << "Derived虚函数表 — 第四个函数内容:";
pFun(); // base1::i
std::cout << std::endl;
std::cout << "Derived虚函数表 — 第五个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 4 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 4 * (sizeof(int*) / sizeof(int)))));
std::cout << "Derived虚函数表 — 第五个函数内容:";
pFun(); // base2::h1
std::cout << std::endl;
std::cout << "Derived虚函数表 — 第六个函数地址:" << (*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 5 * (sizeof(int*) / sizeof(int))))) << std::endl;
pFun = reinterpret_cast<Fun>(*(reinterpret_cast<int**>(*(reinterpret_cast<int**>(&Derived)) + 5 * (sizeof(int*) / sizeof(int)))));
std::cout << "Derived虚函数表 — 第六个函数内容:";
pFun(); // Derived::i1
std::cout << std::endl;
return 0;
}