如下測試代碼:
#include<iostream>
using namespace std;
class base
...{
public:
base()
...{
cout<<"create base"<<endl;
};
virtual ~base()
...{
cout<<"clean base"<<endl;
};
virtual void foo_1() = 0;
virtual void foo_2();
void foo_3();
};
//實現
void base::foo_2()
...{
cout<<"virtual base::foo_2"<<endl;
}
void base::foo_3()
...{
cout<<"isnt virtual base::foo_3"<<endl;
}
//繼承類
class inherit :public base
...{
public:
inherit()
...{
cout<<"create inherit"<<endl;
};
~inherit()
...{
cout<<"clean inherit"<<endl;
};
//virtual void foo_0() = 0;
virtual void foo_1();
virtual void foo_2();
void foo_3();
};
//實現
void inherit::foo_1()
...{
cout<<"virtual inherit::foo_1"<<endl;
}
void inherit::foo_2()
...{
cout<<"virtual inherit::foo_2"<<endl;
}
void inherit::foo_3()
...{
cout<<"isnt virtual inherit::foo_3"<<endl;
}
int main()
...{
base* ptr = new inherit;
ptr->foo_1();
ptr->foo_2();
ptr->foo_3();
delete[] ptr;
int nWait;
cin>>nWait;
return 0;
}
在VC7下測試:
create base
create inherit
virtual inherit::foo_1
virtual inherit::foo_2
isnt virtual base::foo_3
clean inherit
clean base
從結果中可以得出如下兩點結論:
(1)指向衍生類別的基類指標所調用的虛函數的為衍生類別中的;
(2)指向衍生類別的基類指標所調用的類函數(非虛擬函數,非靜態函數)為原指標類型所在的函數;
那麼可以得知虛函數和非虛函數在類中的布局不一樣;
那麼基類類型的指標是怎麼實現調用非衍生類別的函數呢?
原因為
每個含有虛函數的類都存在一張虛函數表(vtb),這張虛表是在編譯期產生的。
然後每個類的對象都有一個指向虛表的指標,在虛表中可以調用相應的函數。
那麼繼續分析上面的例子,
由於
base* ptr = new inherit;
操作,將產生inherit對象,在inherit的建構函式執行期間,完成inherit的vtb建立過程,同時建立出的inherit中自動產生一個指標指向該vtb。
線面將分別解釋上面結論(1)和(2)
由於ptr的地址是指向inherit的對象,但是指標類型依然是基類的。
在調用虛函數時,首先調用指向vtb的指標我們姑且稱該指標為ptrVtb,然後通過該函數的索引值來取得vtb中的相對的值。
由於類函數(非虛擬函數,非靜態函數)的地址不在類的具體對象中,所以利用ptr調用類函數(非虛擬函數,非靜態函數)調用的還是基類的函數!