Ⅰ C++虛表問題
虛函數表是編譯器用來實現多態的方法。一般來說,虛函數表是一個數組,數組的元素是虛函數的指針。每個對象都會有一個虛函數表,當在某個對象上調用虛函數時,通過查詢這個表來獲得繼承層次中到底哪個函數被實際調用。
對於一個類如果有虛函數,就會在這個類中創建一個虛表,也就會產生一個虛指針指向這個虛表。
既然有一個指針指向了虛表,這個類派生後,在派生類中就不必再創建虛表,如果派生類還有自己的虛函數,那麼只在派生類中創建該虛函數的一個虛表,產生一個指向該虛表的指針。
為每個類設置虛表,初始化虛指針,為虛函數調用插入代碼都是自動發生的,不必擔心這些。
(我看到過虛繼承下虛表問題的分析,直接繼承下沒看過,特此又分析了一下,修改)
#include<iostream>
using namespace std;
class A
{
public:
virtual void a(){};
};
class B:public virtual A
{
public:
virtual void b(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
}
對於這個程序,你大概是在vc6.0下運行的吧,在vc下結果是4和12。我用的編譯器是g++,對於這段程序的結果確實都為4.
因編譯器不同導致結果不同這個我倒是沒注意,這樣可以得出,對虛函數這里的處理機制和編譯器也是有關的,g++編譯器還是更符合新的標准。
把虛繼承virtual去掉再運行,在codeblocks下,g++編譯運行結果都為4. vc下編譯運行結果也都為4.
在分析一個例子:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public A
{
char k[3];
public:
virtual void b(){};
};
class C:public B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
這個直接繼承的例子,在vc下,codeblocks下結果都為 8 12 16.
再看這個直接繼承的例子:
#include<iostream>
using namespace std;
class A
{
public:
virtual void a(){};
};
class B:public A
{
public:
virtual void b(){};
};
class C:public B
{
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
vc下河codeblocks下結果都為 4. 這兩個程序說明,直接繼承下,輸出結果應當是本類所佔的位元組加父類數據成員所佔位元組,父類的虛指針所佔位元組沒有加上。
加入虛繼承後:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public virtual A
{
char k[3];
public:
virtual void b(){};
};
class C:public virtual B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
這段代碼,在codeblocks下g++編譯運行結果為:8 16 24.
在vc6.0下編譯運行結果為:8 20 32.
能夠分析出codeblocks下的結果是本類加上父類的結果。vc下是 本類加父類後又加了4個位元組。
但是這段代碼:
#include<iostream>
using namespace std;
class A
{
public:
virtual void a(){};
};
class B:public virtual A
{
public:
virtual void b(){};
};
class C:public virtual B
{
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
codeblocks下編譯運行結果為 4 4 4.
vc下編譯運行結果為:4 12 20.
從結果來看,vc下是 本類加父類後又加了4個位元組。而codeblocks結果就不再是本類加父類的結果(這個有點迷茫)。