次の記事はよく話します。
http://www.cnblogs.com/lihaosky/articles/1606502.html
私たちは、このようなクラスがあるとします。
クラスBase {
公:
仮想ボイドF(){COUT << "ベース:: F" <<>
仮想空隙G(){COUT << "ベース:: G" <<>
仮想ボイドH(){COUT << "ベース:: H" <<>
}。
上記の引数によると、私たちは、Baseの一例として仮想関数テーブルを取得することができます。ここでは、実際のルーチンです。
typedefは無効(*楽しい)(無効)。
ベースB;
楽しいpFun = NULL;
裁判所未満<< "仮想関数テーブルアドレス:" <<(int型*)(&B)<<>
裁判所未満<< "仮想関数テーブル - 関数の最初のアドレス:" <<(int型*)*(int型*)(&B)<<>
//最初の仮想関数を呼び出します
pFun =(楽しい)*((int型*)*(int型*)(&B))。
pFun();
次によって実際の業績:(Windows XPの+ VS2003、Linuxの2.6.22 + GCC 4.1.3)
仮想関数テーブルアドレス:0012FED4
Vtable - 関数の先頭アドレス:0044F148
ベース:: F
この例を通じて、我々は、*&B int型に変身する仮想関数テーブルのアドレスを取得し、その後、あなたが最初の仮想関数のアドレスを取得することができ、再びサイトをチェック強制することができていることがわかります、それは、ベースである:: F ()、上記の手順で確認された(INT *が強制的関数ポインタになりました)。あなたがベース::グラム()とベース:: Hを()を呼び出している場合は、この例を通じて、私たちが知ることができ、以下のように、そのコードは次のとおりです。
(楽しい)*((int型*)*(int型*)(&B)0); //ベース:: F()
(楽しい)*((int型*)*(int型*)(&B)+1); //ベース::グラム()
(楽しい)*((int型*)*(int型*)(&B)2)。//ベース:: H()
*注:実際には自分のマシン上で上記のコードは、基地:: G()と塩基:: Hを印刷することはできません()。そのint型のポインタに加えて4つのバイトを追加し、それが楽しいのサイズを取得するのがベストですので、セグメンテーションフォールトをプリントアウトするために、関数ポインタのサイズは8バイトであることがわかり、その後私のマシン上に、彼によると追加されますプラス2は正しくgおよびhを再生することができます。
継承の一般的な(非仮想関数のオーバーライド)
一般承継(カバーは、仮想関数を持っています)
多重継承(なし仮想関数のオーバーライド)
私たちは見ることができます:
1)各クラスは、独自の仮想親テーブルを持っています。
メンバ関数2)サブクラスの表は、親クラスに入れました。(呼び出さ親クラスが宣言に従って決定された第1の順序で)
多重継承(仮想関数がカバー持っています)
私たちは今、悪い何かをするために、仮想関数テーブルを使用することができます参照してください。
、親の型サブクラスを通じてポインタにアクセスする独自の仮想関数
私たちは何の仮想関数のオーバーロードのサブクラスは親クラスが無意味なものではないことを知っています。多型は、関数のオーバーロードに基づいてされるので。私たちが見ることができますがBASE1仮想テーブルは、上の図に仮想関数を導出持っているが、我々は単純に、独自の仮想関数サブクラスを呼び出すために、次のステートメントを使用することはできません。
BASE1 * B1 =新しい派生();
B1-> F1(); //コンパイルエラー
任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,所以,这样的程序根本无法编译通过。但在运行时,我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。(关于这方面的尝试,通过阅读后面附录的代码,相信你可以做到这一点)
二、访问non-public的虚函数
另外,如果父类的虚函数是private或是protected的,但这些非public的虚函数同样会存在于虚函数表中,所以,我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数,这是很容易做到的。
如:
class Base {
private:
virtual void f() { cout << "Base::f" <<>
};
class Derive : public Base{
};
typedef void(*Fun)(void);
void main() {
Derive d;
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);
pFun();
}