2011-07-07 50 views
5

我讀了一些C++的文本,得到了下面的代碼:關於C++類型一致性的問題?

class A { }; 
class B : public A { }; 

void main() { 
    A* p1 = new B; // B may be larger than A :OK [Line 1] 
    B* p2 = new A; // B may be larger than A :Not OK [Line 2] 
} 

我有2個問題:

  1. 我不明白筆者在1號線和2號線
  2. 評論意思
  3. 爲什麼我們不能在第二行做?
+1

事實上,由於空基類優化和一些奇怪的ABI佈局,我認爲'A'可能比'B'大。 –

回答

8

嘛, 「大」 是不是這裏的關鍵。真正的問題是「是」的關係。

class B任何目的還class A型的(class Bclass A由於繼承),所以,第一行是行(指針class A可以一樣好指向的class B一個目的),但逆是不正確的(class Aclass B,甚至可能沒有class B存在的想法),所以第二行不會編譯。

0

由於B從A衍生,指針B *不能指向A.

0

B* p2 = new A;是無效的,因爲一個指針到B可以期望B有更多的信息比A

例子:

class B : public A { 
public: 
    int notInA; 
}; 

B* p2 = new A; 
p2->notInA = 5; // Wait, which notInA are we talking about? 
       // p2 is really an A, and As don't have notInA! 
7

作者是向你表明他不理解C++(或一般程序)。沒有涉及規模(「更大」)的問題。問題是,B「ISA」 A,所以指針A可以用指針B初始化。但事實並非如此。

+0

有很多不好的C++書籍,我都爲不熟悉的初學者哭泣。 –

1

的意見是愚蠢的,真的。對象的大小與它沒有太大的關係。問題是你可以隱式地上傳指針類型,但不能向下轉發。

順便說一下,main必須有返回類型int。不是void

0

當使用一個指針的指針值是存儲器位置。這意味着你可以設置一個指針指向內存中的任意點。爲了「解除引用」該內存並且與當時存儲的對象一起工作,您需要知道期望的對象類型
當乙類繼承的類,B將包括一個 「A」。銳利是正確的說有一個「是-A」關係。 「B」是 - 「A」,但「A」不是「B」。
問題將是完全一樣的在下面的代碼:

string* s = new string(""); 
int a = 44; 
s = (string*)&a; //compiler error if not cast 
cout << s; // randomness printed. 
0
class B : public A { }; 

A* p1 = new B; // B may be larger than A :OK [Line 1] 
B* p2 = new A; // B may be larger than A :Not OK [Line 2] 

我不明白筆者在1號線和2號線
評論意味着我們爲什麼不能在2號線做?

class Bclass A派生,它 - 從它所包含的成員變量的角度看 - 意味着它有一切有和任何它選擇將自身添加。在你簡單的代碼中,B沒有添加任何東西,但是如果它確實有其他數據成員,它顯然需要更多的內存來存儲比簡單的A類型。如果它添加了一個虛擬成員函數,其中A沒有,那麼編譯器可能會在B中添加一個指針,該指針記錄虛擬調度表的地址,其中列出了其virtual成員函數的地址。如果感覺像編譯器一樣,編譯器也可以自由添加填充。

因此,一般情況下派生類的大小是其基類大小的>=

A* p1 = new B; // B may be larger than A :OK [Line 1] 

這裏,但是太多的空間B實際需要正在從堆/空閒存儲分配,並存儲在p1內存的地址。如果B大於A,則沒有區別 - 這就是其他地方 - 關鍵是B*保證能夠存儲在A*中。

B* p2 = new A; // B may be larger than A :Not OK [Line 2] 

這裏,被在堆上創建了一個新A,但程序員是想告訴編譯器,有一個B在該地址。編譯器不會相信它(除非被迫) - 你只會得到編譯器時間錯誤。如果你強迫編譯器(如P2 =(B *)(新一)) to treat the memory address in P2 as if it were an, then it may later try to access additional data it expects to be part of anywhich simply doesn't exist in any A`:額外的數據成員,虛擬調度指針等。這裏

1

大家都把正確的答案,但我想指出,筆者的意思是「大」,等等。
考慮這兩個類:

class Animal { 
    public: 
    bool bIsHungry; 
}; 

class Bird : public Animal { 
    public: 
    bool bIsFlying; 
} 

後來,當我打電話

Animal* animal = new Bird; // B may be larger than A :OK [Line 1] 

程序分配足夠的空間以適應變量「bIsHungry」和變量「bIsFlying」。 (但是除非你強制轉換「動物」,你將只能訪問「bIsHungry」,即使「bIsFlying」也預留給「動物」的記憶。)

當你調用

Bird* parrot = new Animal; // B may be larger than A :Not OK [Line 2] 

該程序只分配足夠的空間來適應變量「bIsHungry」。然而的「鸚鵡」的用戶可能需要編寫代碼,如

if(parrot->bIsFlying) 
{ //doSomething() 
    ... 
} 

這是行不通的,因爲「新的動物」,該方案僅適用於動物類分配的空間,即「bIsHungry」和有沒有分配給「bIsFlying」的內存。編譯器已經「看到」並將「抱怨」,即報告錯誤。

+0

非常感謝一個明確的例子。 – ipkiss