マルチステートのコア--虚関数--静的タイプと動的タイプ
静的タイプ(コンパイル時に知られる参照タイプまたはポインタタイプ)
ダイナミックタイプ(ポインタまたは参照バインドされたオブジェクトのタイプ実行時にのみわかります)
なぜコンパイルが通らないのですか?
(publicに設定した場合、出力:B init 10)
プロセス:
1,コンパイル段階でp->fun()静的タイプで処理するだけで、ここではタイプAです.
すなわち、p->fun();コンパイラはAを呼び出すfunとして対応するチェックと処理を行う.
たとえばAクラスでfun()をprivateに設定した場合、クラスユーザはアクセスできないため、コンパイルエラーが発生します.
2、運転時、
B b; この文は以下の操作を実行します:(PS:クラスの非静的メンバー関数はいずれもポインタパラメータをコンパイルして、その関数を呼び出すオブジェクトを指して、私たちが普段使っているthisはそのポインタの値です)
(1)ベースクラスのコンストラクション関数を呼び出し,付加的なthisポインタ(bを指す)により,bに対応する虚関数数テーブルの第1項を:A::fun(int)に変更する.
(2)派生クラスのコンストラクション関数を呼び出し,付加されたthisポインタ(bを指す)を越え,bに対応する関数テーブルの第1項を:B:fun(int)に変更し,さっきのオーバーライドを行う.
PS:虚関数表の各項目には関数ポインタが保存されており、最後の項目は終了マークです.
従ってp->fun()を実行する.の場合、実際に実行するB::fun()です.
なぜ出力10
C++の注意条項に「継承されたデフォルトパラメータ値を再定義しない」(Effective C++Item 37,never redefine a function's inherited default parameter value)があるのも同様です.
ベースクラスの参照またはポインタで虚関数を呼び出すが、実際に派生クラスで定義されたバージョンが実行されている場合、問題が発生する可能性があります.
この場合、虚関数のベースクラスバージョンに定義されたデフォルトの実パラメータは、派生クラス定義のバージョンに渡され、派生クラスバージョンは異なるデフォルトの実パラメータで定義されます.
詳細については、http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html
ダイナミックタイプ(ポインタまたは参照バインドされたオブジェクトのタイプ実行時にのみわかります)
#include <iostream>
using namespace std;
class A
{
public:
A()
{
fun();
};
//private: // private
virtual void fun(int i=10)
{
cout<<"A init; "<<i<<endl;;
}
};
class B:public A
{
public:
B(){
cout<<"B init2"<<endl;
};
virtual void fun2()
{
cout<<"B fun2 "<<endl;
}
virtual void fun(int i=88)
{
cout<<"B init "<<i<<endl;
}
};
int main()
{
B b;
A* p=&b;
p->fun();
system("pause");
return 0;
}
なぜコンパイルが通らないのですか?
(publicに設定した場合、出力:B init 10)
プロセス:
1,コンパイル段階でp->fun()静的タイプで処理するだけで、ここではタイプAです.
すなわち、p->fun();コンパイラはAを呼び出すfunとして対応するチェックと処理を行う.
たとえばAクラスでfun()をprivateに設定した場合、クラスユーザはアクセスできないため、コンパイルエラーが発生します.
2、運転時、
B b; この文は以下の操作を実行します:(PS:クラスの非静的メンバー関数はいずれもポインタパラメータをコンパイルして、その関数を呼び出すオブジェクトを指して、私たちが普段使っているthisはそのポインタの値です)
(1)ベースクラスのコンストラクション関数を呼び出し,付加的なthisポインタ(bを指す)により,bに対応する虚関数数テーブルの第1項を:A::fun(int)に変更する.
(2)派生クラスのコンストラクション関数を呼び出し,付加されたthisポインタ(bを指す)を越え,bに対応する関数テーブルの第1項を:B:fun(int)に変更し,さっきのオーバーライドを行う.
PS:虚関数表の各項目には関数ポインタが保存されており、最後の項目は終了マークです.
従ってp->fun()を実行する.の場合、実際に実行するB::fun()です.
なぜ出力10
C++の注意条項に「継承されたデフォルトパラメータ値を再定義しない」(Effective C++Item 37,never redefine a function's inherited default parameter value)があるのも同様です.
ベースクラスの参照またはポインタで虚関数を呼び出すが、実際に派生クラスで定義されたバージョンが実行されている場合、問題が発生する可能性があります.
この場合、虚関数のベースクラスバージョンに定義されたデフォルトの実パラメータは、派生クラス定義のバージョンに渡され、派生クラスバージョンは異なるデフォルトの実パラメータで定義されます.
詳細については、http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html