一般來說,乙個重寫的函式與被它重寫的函式必須具有相同的返回型別:
class shape ;
class circle : public shape ;
然而,這個規則對於」協變返回型別(covariant return type)」的情形來說有所放鬆.也就是說,若b是乙個類型別,並且乙個基類虛函式返回b *,那麼乙個重寫的派生類函式可以返回d *,其中的d公有派生於b(即d是乙個(is-a)b).若基類虛函式返回b &,那麼乙個重寫的派生類函式可以返回乙個d&.考慮如下乙個shape層次結構的clone操作:
class shape ;
class circle : public shape ;
重寫的派生類函式被宣告為返回乙個circle *而不是乙個shape *.這是合法的,因為circle是乙個shape.注意如乙個circle被當作shape進行操作,從返回的circle *就回被自動轉化為shape *:
shape *s1 = getacircleorothershape ();
shape *s2 = s1->clone();
當直接操縱派生型別而不是通過其基類介面來操縱它們時,使用協變返回型別的優勢就會體現出來了:
circle *c1 = getacircle();
circle 8c2 = c1->clone();
如果沒有協變返回機制,circle::clone將不得不精確的匹配shape::clone的返回型別,從而返回乙個shape *.我們就被迫將返回結果轉換為circle *.
circle *c1 = getacircle();
circle *c2 = static_cast( c1->clone());
再看另外乙個例子。考慮如下shape的factory method成員,它返回乙個引用,指向與具體的形狀對應的形狀編輯器:
class shapeeditor ;
class shape ;
//….
class circle;
class circleeditor : public shapeeditor ;
class circle : public shape;
在這個例子中,注意circleeditor必須在circle::geteditor的宣告之前被完整地定義(而不能僅僅宣告)。因為編譯器必須知道circleeditor物件的布局,才能執行適當的位址操縱,從而將乙個circleeditor引用(或指標)轉換為乙個shapeeditor引用(或指標)。
協變返回型別的優勢在於,總是可以在適當程度的抽象層面工作。若我們是處理shape,將獲得乙個抽象的shapeeditor;若正在處理某種具體的形狀型別,比如circle,我們就可以直接獲得ciecleeditor.協變返回機制將我們從這樣的一種處境解脫出來:不得不使用易於出錯的轉換操作來「重新」提供型別資訊,而這種資訊是一開始就不應該丟掉的:
shape * s = getacircleorothershape ();
const shapeeditor &sed = s->geteditor();
ciecle *c =getacircle();
const circleeditor &ced = c->geteditor();
C 返回型別協變
在c 中,只要原來的返回型別是指向類的指標或引用,新的返回型別是指向派生類的指標或引用,覆蓋的方法就可以改變返回型別。這樣的型別稱為協變返回型別 covariant returns type 返回型別協變 覆蓋要求函式具有 完全相同的入參 一般覆蓋具有相同的返回值,否則會提示錯誤 virtual d...
c 返回型別協變
在c 中,只要原來的返回型別是指向基類的指標或引用,新的返回型別是指向派生類的指標或引用,覆蓋的方法就可以改變返回型別。這樣的型別稱為協變返回型別 covariant returns type 覆蓋要求函式具有完全相同的入參。一般覆蓋具有相同的返回值,否則會提示錯誤 virtual double a...
協變和逆變
協變和逆變都是術語,前者指能夠使用比原始指定的派生型別的派生程度更大的型別,後者指能夠使用比原始指定的派生型別的派生程度更小的型別。using system using system.collections.generic using system.text class derived base s...