多重繼承下,不同基類指針指向同一子類對象的地址問題——騰訊一筆試題


原文:http://www.haogongju.net/art/1694028

多繼承時,父類指針指向子類對象時,父類指向的不是子類開始地址,而是子類中對應父類的結構的類對象的基地址,所以,當多個父類指向同一個子類時,父類的指針值其實是不一樣的。


5.觀察下面一段代碼: 
class ClassA 

public: 
virtual ~ ClassA(){}; 
virtual void FunctionA(){}; 
}; 


class ClassB 

public: 
   virtual void FunctionB(){}; 
}; 


class ClassC : public ClassA,public ClassB 

public: 
}; 
  
ClassC aObject; 
ClassA* pA=&aObject; 
ClassB* pB=&aObject; 
ClassC* pC=&aObject; 


關於pA,pB,pC的取值,下面的描述中正確的是: 
A.pA,pB,pC的取值相同.               B.pC=pA+pB 
C.pA和pB不相同                      D.pC不等於pA也不等於pB


這個是多重繼承的問題。在《Thinking in C++》第二卷的363頁看到重複子對象這部分的內容,明白了怎麼回事。

以上兩個基類均含有虛函數,故其大小至少有一個虛函數表的指針大小,結構大概是這樣的:


ClassA類數據成員
ClassB類數據成員
ClassC類其他數據成員

可以看出對象aObject以ClassA子對象開頭,然後是ClassB子對象部分,最後的部分來自ClassC類本身。ClassC的對象既是一個ClassA也是一個ClassB。

故aObject可以向上類型轉換到兩者中任何一個基類型。


當向上類型轉換爲ClassA時,結果指針指向ClassA子對象部分,剛好在ClassC對象的開始位置,所以地址pA和pC是相同的。

當向上類型轉換到ClassB時,結果指針必須指向ClassB子對象所在的實際位置,因爲類ClassB並不知道有關ClassC的事情。

所以上題的答案應爲C。


但是這個地方有個好玩的現象:

如果添加如下代碼:cout<<"pC==pB?"<<boolalpha<<(pC==pB)<<endl;

則返回值永遠都是true,儘管他們的地址輸出的時候並不相同。因爲pC在pC==pB的過程中被隱式轉換爲ClassB*,以使得比較有意義。




基類子類在內存中的存儲

class a 
{

public: 
int aa

}; 


class b:public a 
{

public: 
int bb; 

從內存的來看 
如a 
---------| 
|佔一個int數據大小--| 
|----(aa數據)------| 
|--------- 
而b則是 
---------|--------- 
|佔一個int數據大小--|佔一個Int數據大小--| 
|從a中繼承而來------|---(bb數據----------| 
|------------------ 
當定義一個基類類型的指針時 
a *p;這時,這個指針指向的是a類型的數據 
當p指針指向派生類的時候,因爲p是a類型的指針,所以*p只解釋爲a類型數據的長度,即 
————————-|--------- 
|佔一個int數據大小--|佔一個Int數據大小--| 
|從a中繼承而來------|-----(bb數據)-------| 
|------------------ 
|------------|------------| 
|-p只指向這個區域_--| 

因此,當基類的指針(P)指向派生類的時候,只能操作派生類中從基類中繼承過來的數據。 
指向派生類的指針,因爲內存空間比基類長,會導致嚴重了後果,所以不允許派生類的指針指向基類。而基類的指針可以指向派生類。 

C++的多態性能解決基類指針不能操作派生類的數據成員的問題。

 

用C++比較好說明白:       
  1:指針的可訪問性是由指針的定義決定的,比如說用BaseClass定義的指針,可訪問的範圍就是BaseClass的內存區域       
  2:允許用一個指向基類的指針指向派生類,由於被指向的對象的內存空間大於指針的可訪問空間,所以這種向上映射是安全的       
  3:對象在調用虛函數的時候,是調用父類的函數還是調用派生類的函數,是和對象的類型有關的,比如說一個派生類B,其父類是A,則B的對象調用父類中被聲明爲VIRTUAL的函數時,被B   所OVERRIDE的函數調用的是B裏的函數,而B沒有OVERRIDE的函數調用的是基類裏的函數 

發佈了19 篇原創文章 · 獲贊 40 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章