派生類轉換爲基類,hierarchy向上走,稱爲upcasting;基類轉換爲派生類,hierarchy向下走,稱爲downcasting。downcasting是不安全的,一般不被允許。
含有虛函數的類,編譯器給每個對象添加一個隱藏成員,該成員保存一個指向函數地址數組的指針。這個函數地址數組包含了類的所有虛函數地址。如果派生類覆蓋了基類的虛函數,那麼這個數組中相應的元素也被覆蓋;如果派生類增加了一個虛函數,那麼會在數組中增加一個元素。不管虛函數數目是1還是10,都只在對象中添加一個地址成員,只是表的大小不同而已。
返回類型協變
覆蓋要求函數具有完全相同的入參。
一般覆蓋具有相同的返回值,否則會提示錯誤
virtual float area () const ; //編譯器提示錯誤,返回類型不同
這個規則對返回類型協變而言,則有所放鬆。覆蓋的返回值不區分基類或派生類。從語意上理解,一個派生類也是一個基類。如下:
Class Shape
{
public:
virtual const ShapeEditor & getEditor () const = 0; //Factory Method
};
Class Circle;
Class CircleEditor : public ShapeEditor { … };
Class Circle : Public Shape
{
public:
const CircleEditor &getEditor () const ;
};
在這個例子中,注意CircleEditor必須在Circle::getEditor的聲明之前被完整地定義(而不能僅僅聲明),
因爲編譯器必須知道CircleEditor對象的佈局,才能執行適當的地址操縱,從而將一個CircleEditor引用
(或指針)轉換爲一個ShapeEditor引用(或指針)。
協變返回類型的優勢在於,總是可以在適當程度的抽象層面工作。若我們是處理Shape,將獲得一個抽象的ShapeEditor;若正在處理某種具體的形狀類型,比如Circle,我們就可以直接獲得CiecleEditor.協變返回機制將我們從這樣的一種處境解脫出來:不得不使用易於出錯的轉換操作來“重新”提供類型信息,而這種信息是一開始就不應該丟掉的:(那麼,對於友元,派生的operator+,怎麼樣調用基類的operator+呢?)
Const ShapeEditor &sed = s->getEditor();
Ciecle *c =getACircle();
Const CircleEditor &ced = c->getEditor();