1.基類與派生類的內存分配
派生類繼承基類
內存分配時,是在於基類對象不同的內存地址處,按基類的成員變量類型,開闢一個同樣的類型空間,但注意開闢後派生對象的空間,不是複製基類的成員的值,而是僅僅開闢那種成員類型的空間,未初始化時,裏面存在的數是不確定的
然後派生類自己定義的成員變量是排在繼承的A類成員下面,如果派生類定義的變量名與基類相同,則此變量覆蓋掉繼承的基類同名變量,注意,覆蓋不是刪除,也 就是派生類中繼承自基類的成員變量依然存在,而且值也不發生變化。如果想用此繼承自基類的成員變量,則要加:: , 在成員函數中訪問時,直接用base::i,即可,用派生類的對象a訪問時,如果此繼承自基類的成員變量是對象可訪問的(Public類型),則用 a.base::i訪問之
Base base;
Sub_class sub;
base.i;
base.j
但是用對象訪問派生類的繼承自基類的成員變量時(假定public類型)
得用:
sub.Base::i
sub.Base::j
直接用sub.i, 訪問的是子類自定義的i
如 以下程序
- class base{
- public:
- int i;
- int j;
- };
- class sub:public base{
- public:
- int i;
- int j;
- void p(){
- cout<<base::i<<endl;
- cout<<base::j<<endl;
- }
- };
- base b;
- sub s;
- b.i=1;
- b.j=2;
- s.i=3;
- s.j=4;
- s.p(); // 輸出兩個不確定的數 4425598 4421322
- cout<<b.i<<endl; // 1
- cout<<b.j<<endl; // 2
- cout<<s.i<<endl; // 3
- cout<<s.j<<endl; // 4
- cout<<s.base::i<<endl;
- cout<<s.base::j<<endl;
4425598
4421322
1
2
3
4
4425598
4421322
Press any key to continue . . .
從派生類對象繼承的兩個基類變量的值和及基類對象兩個成員變量的值得比較看,足以驗證上述結論:
子類繼承的基類的成員,只是在另一個內存空間內開闢一個這種類型的成員變量,它的值並不是基類的值,編譯器只是負責把這一部分空間類型設置爲與基類的類型相同
2 普通類的內存分配
(一)
class CBase
{
};
sizeof(CBase)=1;
爲什麼空的什麼都沒有是1呢?
c++要求每個實例在內存中都有獨一無二的地址。//注意這句話!!!!!!!!!!
空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之後就有了獨一無二的地址了。所以空類的sizeof爲1。
class CBase
{
int a;
char p;
};
sizeof(CBase)=8;
記得對齊的問題。int 佔4字節//注意這點和struct的對齊原則很像!!!!!
char佔一字節,補齊3字節
(三)
class CBase
{
public:
CBase(void);
virtual ~CBase(void);
private:
int a;
char *p;
};
再運行:sizeof(CBase)=12
C++ 類中有虛函數的時候有一個指向虛函數的指針(vptr),在32位系統分配指針大小爲4字節。無論多少個虛函數,只有這一個指針,4字節。//注意一般的函數是沒有這個指針的,而且也不佔類的內存。
(四)
class CChild : public CBase
{
public:
CChild(void);
~CChild(void);
virtual void test();
private:
int b;
};
輸出:sizeof(CChild)=16;
可見子類的大小是本身成員變量的大小加上父類的大小。//其中有一部分是虛擬函數表的原因,一定要知道
父類子類共享一個虛函數指針
(五)
總結:
空的類是會佔用內存空間的,而且大小是1,原因是C++要求每個實例在內存中都有獨一無二的地址。
(一)類內部的成員變量:
- 普通的變量:是要佔用內存的,但是要注意對齊原則(這點和struct類型很相似)。
- static修飾的靜態變量:不佔用內容,原因是編譯器將其放在全局變量區。
- 普通函數:不佔用內存。
- 虛函數:要佔用4個字節,用來指定虛函數的虛擬函數表的入口地址。所以一個類的虛函數所佔用的地址是不變的,和虛函數的個數是沒有關係的。