Covariant return type

峻峰飛陽發表於2015-05-21
class Shape {
  public:
    virtual double area() const = 0;
};
class Circle : public Shape {
  public:
    float area() const; // error! different return type    
};

int
main() {
}

在繼承關係中,子類覆蓋父類的虛擬函式的時候,必須連返回值型別也完全相同。所以上面這個程式編譯是編不過的:
main.cpp:9: error: conflicting return type specified for `virtual float Circle::area() const'
main.cpp:5: error:   overriding `virtual double Shape::area() const'

但是這個限制在所謂的“Covariant return type”的情況下可以被放鬆。如果基類的一個虛擬函式返回值型別是B*,那麼其派生類中覆蓋這個函式的時候,返回值型別可以是D*,其中D是任何以public方式繼承自B的派生類(也就是說D is-a B)。如果基類的虛擬函式返回B&,派生類覆蓋這個函式的時候也可以返回D&。

例如這段程式編譯就沒有問題:

class Shape {
  public:
//    virtual double area() const = 0;
    virtual Shape* clone() const = 0;
};
class Circle : public Shape {
  public:
//    float area() const; // error! different return type
    virtual Circle* clone() const;
};

int
main() {
}

當程式通過指向基類(介面)的指標操縱不同的派生類(實體類)的物件時,派生類方法返回的D*/D&型別的值,可以被自動轉換為B*/B&型別。

=================

看下面的例子。要點:返回值(A*,B*)涉及到的類,和虛擬函式所在的類(C和D),可以分屬於兩個完全不同的繼承體系。

class A { };
class B: public A { };
class C {
  public:
    virtual A* getA() const = 0;
};
class D: public C {
  public:
    B* getA() const;
};

這段程式編譯沒有錯誤。

注意:
需要包含繼承類標頭檔案,光是型別宣告是不行的。

相關文章