2011-01-28 205 views
10

虛函數的返回類型應該與基類或協變類型相同。但爲什麼我們有這個限制?虛函數的返回類型不同

+0

您預計覆蓋函數的返回類型被允許是...? – curiousguy 2012-08-07 18:20:45

回答

5

因爲使用返回值的代碼如何處理各種無關的類型回來?例如: -

class A 
{ 
public: 
    virtual float func(); 
}; 

class B: public A 
{ 
public: 
    virtual char *func(); 
}; 

A *p = (some_condition) ? new A() : new B(); 
p->func(); // Oh no! What is the type? 
+0

是的,不相關的類型=錯誤。其他相關類型呢? – curiousguy 2012-08-09 00:15:25

13

,因爲這會引發很多的廢話:

struct foo 
{ 
    virtual int get() const { return 0; } 
}; 

struct bar : foo 
{ 
    std::string get() const { return "this certainly isn't an int"; } 
}; 

int main() 
{ 
    bar b; 
    foo* f = &b; 

    int result = f->get(); // int, right? ...right? 
} 

這是不明智的有一個派生類的東西回報完全無關。

+0

討論[轉移到聊天。](http://chat.stackoverflow.com/rooms/15288/discussion-between-gmannickg-and-curiousguy) – GManNickG 2012-08-13 19:08:53

+0

結束聊天:** GManNickG承認,目前的C++規則只有允許指針(或引用)可以放鬆。** – curiousguy 2012-08-13 19:42:54

+0

不是「承認」,我從來沒有否認它首先... – GManNickG 2012-08-14 02:02:08

3

根據C++標準:

壓倒一切的函數的返回類型應是等同於重寫FUNC- 和灰或協變與函數的類的返回類型。如果函數d :: F覆蓋的函數B :: f,其 返回類型的功能是協變如果滿足以下條件:

1)兩者都是類型指針或引用類

2)B :: f的返回類型中的類與D :: f的返回類型中的類相同,或者是類的明確且可訪問的直接或間接基類返回類型D :: f

3)指針或引用es具有相同的cv資格,並且返回類型D :: f 中的類類型具有與返回類型B :: f中的類類型相同的cv資格或更少的cv資格。

1

答案與Bjarne Stroustrup常見問題的"Why can't I assign a vector<Apple*> to a vector<Fruit*>?"的答案非常相似。

在處理多態類型時,修改返回類型的能力會導致語言類型安全性的一個漏洞(請參閱@GManNickG的答案,瞭解具體示例)。

當影響返回類型是理想的時候,有一種相當常見的情況:當從基類型的虛擬方法返回多態指針時。例如,

class Base { 
public: 
    virtual Base* parent() = 0; 
}; 

class Child : public Base { 
public: 
    Base* parent() override 
    { 
     return parent_; 
    } 
private: 
    Parent* parent_; // Assume `Parent` type exists. 
}; 

在這裏,我們失去了類型信息Child知道它是parent_成員。這導致大量的鑄造,即使這種類型是在一個明確定義的點。我們可以解決這個使用Curiously Recurring Template Parameter(CRTP)成語,

template<class ParentType> 
class Base { 
public: 
    virtual ParentType* parent() 
    { 
     return parent_; 
    } 

private: 
    ParentType* parent_; 

}; 

class Child : public Base<Parent> { 
};