2010-05-11 142 views
0

我有點糊塗:C++鍵入和OOP子類

  • 如果我有一個基類A,並且其延伸的一個類B,可以在類型A的變量保持的值B型,反之亦然?

如果是,爲什麼?即使B是從A派生出來的,它們是不是完全不同?類型安全如何?

  • 如果這是可能的,當我使用這個時需要注意什麼? 這將如何解決性能方面的問題?

注:對不起,如果我問太多問題,不理會他們,只是看出來的那些名單裝飾點「標記」 :) 而且,這也不是我的功課。我是一名業餘愛好程序員,擁有使用OOP編寫腳本語言的技能,但對於使用C++進行OOP打字的人來說,我還是比較陌生。

+0

也許提供一些代碼作爲例子:) – 2010-05-11 20:58:20

+1

爲什麼?我現在沒有任何具體的例子。子類與「父類相同」的規則應該是一般的,或者? – Zack 2010-05-11 20:59:55

+0

沒有具體的例子就是爲什麼你感到困惑。對代碼進行編碼,它會幫助你全力以赴。 – jmucchiello 2010-05-11 21:27:01

回答

3

如果你這樣做:

B b; 
A a = b; 

那麼你得到 「切片」。 a將只包含bA部分。

但你可以有引用/指針:

B b; 
A &ra = b; 
A *pa = &b; 

在這種情況下,rapa只是指/點到真正B對象。這是因爲公共繼承建模了一個IS-A關係。使用更多的描述性名稱更容易理解。可以考慮AAnimalB作爲Baboon。 A Baboon IS-A Animal所以通過使用引用/指針,您可以將它視爲Baboon,因爲它是更通用的Animal類型。

+0

你能解釋一下爲什麼這個指針可以工作嗎?爲什麼C++不會出現輸入錯誤?我的意思是A!= B,或? – Zack 2010-05-11 21:02:26

+1

'A'和'B'是類型,而不是對象(與許多其他類型爲對象的語言不同)。使用指針,'A *'可以指代從A派生的任何東西,並且虛函數將被正確地轉發給派生類的實現。例如。 '動物*動物=新狒狒();動物 - >吃();動物 - >睡眠();如果它們是虛擬的(在動物中)並且在狒狒中被覆蓋,則會調用狒狒類的飲食和睡眠方法。 OTOH,如果你做了'動物a =狒狒'()',一個狒狒會被創造出來,但是然後*切片*,你將剩下一個有效的動物,它不包含任何額外的狒狒。 – 2010-05-11 21:10:16

0

類型A的變量可以保存類型B的值(對於「保留」的某些定義,如其他答案所解釋的),但絕對不能相反。爲了打破一個標準的例子:

class Animal {}; 
class Dog : public Animal {}; 
class Cat : public Animal {}; 

這是合法的,因爲從Cat派生Animal

Cat c; 
Animal& a = c; 

這不是:

Animal a; 
Cat& c = a; 

這是類型安全的,因爲你已經定義它是如此;整個繼承點就是允許發生這種事情,所以你可以繼續調用通用的Animal變量的方法,而不必知道哪些基類碰巧存儲在其中。至於性能問題,調用虛擬方法比較慢,因爲決定實際調用哪種方法(例如,Cat::foo()Dog::foo()比較,取決於存儲在變量中的特定類型的Animal)必須在運行時發生 - 這是稱爲動態調度。與非虛擬方法的決定可以在編譯時

+1

在C++中,您分配給的變量需要是一個引用(您的代碼將被編譯,但它不會像您期望的那樣運行)。代碼應該是'Cat c;動物&a = c;'和'動物a;貓&c = a;'。查看其他答案。 – 2010-05-11 21:14:42

+0

這可能是合法的,但它不是非常有用。正如Ken所說,使用引用(或指針)。 – jmucchiello 2010-05-11 21:25:45

0

指針參考碰巧A類的對象可以指向/參考B類的對象。那是因爲如果B派生自A,那麼B是-aAB類的每個對象都具有類A的所有成員變量和函數,加上B的唯一成員變量和函數。

class A 
{ 
    public: 
     virtual ~A(); 
     void foo(); 
}; 

class B : public A 
{ 
    public: 
     void bar(); 
}; 

A * a = new B; 
a->foo(); // perfectly valid, B inherits foo() from A 
//a->bar(); // compile-time error, bar() is only defined in B 
delete a; // make sure A has a virtual destructor! 

通常,當您想通過虛函數使用多態行爲時使用這種代碼。

0

不是相反的,但表現並不是正確的問題。如果你已經決定要做一個面向對象的設計,不要爲犧牲性能問題而犧牲正確的抽象。不成熟的優化是萬惡之源。祝你好運!