C++ 類物件大小計算(二)含有虛擬函式類
阿新 • • 發佈:2018-12-30
五、包含虛擬函式的類
包含虛擬函式的類,物件生成時,會在類物件當中插入一個指標,這個指標稱做虛擬函式表指標,簡稱虛表指標(vPtr)。該指標指向一個虛擬函式表(簡稱虛表),虛擬函式表中儲存了虛擬函式的入口地址。基類當中有虛擬函式時,會產生該虛擬函式表;建立基類物件,物件中的vPtr會指向該表;呼叫虛擬函式時,是通過vPtr在此表當中尋找函式入口地址的。
當派生類繼承含有虛擬函式的子類時,會複製一份虛擬函式表,派生類如果有與基類中虛擬函式同名的虛擬函式,會在虛擬函式表中覆蓋原來基類的虛擬函式;如果虛擬函式不重名,只會在虛擬函式表中增加一個函式入口。這種機制實現了類的多型。
#include <iostream> using namespace std; class A { public: A(int x=0) { cout<<"A"<<x<<endl; } void printA() { cout<<"Hello A"; } }; class B :public A{ public: B(int x=0) { cout<<"B"<<x<<endl; } virtual void printB() { cout<<"Hello B"; } }; class C : public B{ public: C() { cout<<"C"<<endl; } virtual void printC() { cout<<"Hello C"; } }; int main() { A a; B b; C c; cout<<"size of a:"<<sizeof(a)<<endl; cout<<"size of b:"<<sizeof(b)<<endl; cout<<"size of c:"<<sizeof(c)<<endl; return 0; }
執行結果為:
類A沒有虛擬函式,因此大小仍然是1。類B因為有虛擬函式,其物件當中包含了一個vPtr指標,指標指向類B的虛擬函式表(假設為vTB),該表中儲存了printB的入口地址,因此大小為4。類C因為繼承了類B,也就複製了vTB(設為vTC),其物件中也就包含了指向vTC的虛表指標,該虛表中除了有printB的入口地址外,還包含了printC的入口地址,因此,類C物件大小為4。考慮另一種情況,類C同時繼承了類A、B,類A、B當中都有虛擬函式。如下面的例子:
#include <iostream>
using namespace std;
class A {
public:
A(int x=0) {
cout<<"A"<<x<<endl;
}
virtual void printA() {
cout<<"Hello A";
}
};
class B {
public:
B(int x=0) {
cout<<"B"<<x<<endl;
}
virtual void printB() {
cout<<"Hello B";
}
};
class C : public B, public A{
public:
C() {
cout<<"C"<<endl;
}
void printC() {
cout<<"Hello C";
}
};
int main() {
A a;
B b;
C c;
cout<<"size of a:"<<sizeof(a)<<endl;
cout<<"size of b:"<<sizeof(b)<<endl;
cout<<"size of c:"<<sizeof(c)<<endl;
return 0;
}
執行結果為:
類A、B物件的大小按照上面所說的記憶體很好理解。類C因為同時繼承了類A、B,因此就複製了兩個虛擬函式表,也就有了兩個vPtr,所以大小為8。如果類C有虛擬函式,也會放在其中一張虛擬函式表當中,不會再增加物件大小。