C++虚関数とマルチステート
2853 ワード
ディテソフトウェア学院の唐先生とC++を勉强してからもうしばらく経ちましたが、虚関数の概念がよく分からないことに気づきました.今日は唐先生の授业をもう一度见て、まず関连する知识をまとめました.
一、多態の概念
マルチステート値がクラスのポインタ(参照)でクラスを呼び出す方法の場合、実際のオブジェクトに基づいて呼び出し関数の具体的なターゲットが決定されます.つまり、同じ呼び出し文は実際の実行時に複数の異なる表現形態があります.
二、多態の実現方式
C++はマルチステートの概念を直接サポートし,virtualキーワードを用いてマルチステートをサポートする.virtualによって宣言された関数はクラスに書き換えられた後に多態特性を有する.virtualによって宣言された関数を虚関数と呼ぶ.
三、例一
プログラムの実行結果は次のとおりです.
上記のコードでは,呼び出し関数
四、C++多態の実現原理
1.クラスに虚関数が宣言されると、コンパイラはクラスに虚関数テーブルを生成します. 2.虚関数数テーブルは、メンバー関数アドレスを格納するデータ構造である. 3.虚函数表はコンパイラによって自動的に生成され、メンテナンスされる. 4.virtualメンバー関数アドレスはコンパイラによって虚関数テーブルに格納されます. 5.虚関数テーブルが存在する場合、各オブジェクトには虚関数テーブルを指すポインタがあり、クラスの一番前に配置されます.
次の図は、ダミー関数呼び出しプロセスです.
次の例で説明します.
プログラムの実行結果を下図に示します.
1.
五、構造関数と構造解析関数が虚関数として宣言できるかどうか
1.コンストラクション関数が虚関数になることはできません.コンストラクション関数の実行が終了すると、虚関数テーブルポインタが正しく初期化されるので、コンストラクション関数でマルチステートが発生することはできません. 2.解析関数は虚関数として設計できます.継承関係が発生した場合、親の構造関数は必ず虚関数として実装されます.そうしないと、親ポインタで子クラスオブジェクトを解放するときに子クラスの構造関数を呼び出すことができず、リソースの解放が不完全になります. 3.解析関数でも多状態挙動は起こり得ない.構造関数の実行時に虚関数テーブルポインタが破棄されたため、現在のクラスで定義されているバージョンのみが呼び出されます.トップ 1 ふみ
一、多態の概念
マルチステート値がクラスのポインタ(参照)でクラスを呼び出す方法の場合、実際のオブジェクトに基づいて呼び出し関数の具体的なターゲットが決定されます.つまり、同じ呼び出し文は実際の実行時に複数の異なる表現形態があります.
二、多態の実現方式
C++はマルチステートの概念を直接サポートし,virtualキーワードを用いてマルチステートをサポートする.virtualによって宣言された関数はクラスに書き換えられた後に多態特性を有する.virtualによって宣言された関数を虚関数と呼ぶ.
三、例一
#include #include using namespace std;class Parent
{public: virtual void print()
{ cout <print(); // }int main()
{
Parent p;
Child c;
how_to_print(&p); // Expected to print: I'm Parent.
how_to_print(&c); // Expected to print: I'm Child.
return 0;
}12345678910111213141516171819202122232425262728293031323334353637381234567891011121314151617181920212223242526272829303132333435363738
プログラムの実行結果は次のとおりです.
上記のコードでは,呼び出し関数
void how_to_print(Parent* p)
によって多態性が現れるが,関数のパラメータはいずれもParent* p
であるが,呼び出し後の結果は確かに異なる.次の図はvoid how_to_print(Parent* p)
関数実行フローです.四、C++多態の実現原理
1.クラスに虚関数が宣言されると、コンパイラはクラスに虚関数テーブルを生成します. 2.虚関数数テーブルは、メンバー関数アドレスを格納するデータ構造である. 3.虚函数表はコンパイラによって自動的に生成され、メンテナンスされる. 4.virtualメンバー関数アドレスはコンパイラによって虚関数テーブルに格納されます. 5.虚関数テーブルが存在する場合、各オブジェクトには虚関数テーブルを指すポインタがあり、クラスの一番前に配置されます.
次の図は、ダミー関数呼び出しプロセスです.
次の例で説明します.
#include #include using namespace std;class Parent
{private: int m_data;public:
Parent() : m_data(10)
{
} virtual void print()
{ cout <p: "<p <p): " <p) <data:" <data <p));
fun(); return 0;
}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758591234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
プログラムの実行結果を下図に示します.
1.
sizeof(Child): 8
:Childは、親パラメータから継承されたint m_data;
メンバー変数の4バイトを除いて、4バイト以上を占めていることを示します.この4バイトは虚関数テーブルを格納するために使用されます. 2. data->p: 0x404318
:虚函数表アドレス; 3. data->data:10
:印刷されたのはm_data
に対応する値であり、さらに虚函数表がクラスの一番前に格納され、4バイトを占有していることを証明した. 4. *(data->p): 4204792
:ダミー関数テーブルに格納されている内容は、ダミー関数に対応するエントリアドレス、すなわちvoid print()
のエントリアドレスである.次の文の印刷I'm Child.
で証明できます.五、構造関数と構造解析関数が虚関数として宣言できるかどうか
1.コンストラクション関数が虚関数になることはできません.コンストラクション関数の実行が終了すると、虚関数テーブルポインタが正しく初期化されるので、コンストラクション関数でマルチステートが発生することはできません. 2.解析関数は虚関数として設計できます.継承関係が発生した場合、親の構造関数は必ず虚関数として実装されます.そうしないと、親ポインタで子クラスオブジェクトを解放するときに子クラスの構造関数を呼び出すことができず、リソースの解放が不完全になります. 3.解析関数でも多状態挙動は起こり得ない.構造関数の実行時に虚関数テーブルポインタが破棄されたため、現在のクラスで定義されているバージョンのみが呼び出されます.