2011-01-28 236 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> { 
};