1. 程式人生 > >C++ 類物件大小計算(二)含有虛擬函式類

C++ 類物件大小計算(二)含有虛擬函式類

五、包含虛擬函式的類

        包含虛擬函式的類,物件生成時,會在類物件當中插入一個指標,這個指標稱做虛擬函式表指標,簡稱虛表指標(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有虛擬函式,也會放在其中一張虛擬函式表當中,不會再增加物件大小