继承类是否有可能实现具有不同返回类型的虚函数(不使用模板作为返回)?
答案 0 :(得分:76)
在某些情况下,是的,派生类使用不同的返回类型覆盖虚函数是合法的,只要返回类型是 covariant 与原始返回类型。例如,请考虑以下事项:
class Base {
public:
virtual ~Base() {}
virtual Base* clone() const = 0;
};
class Derived: public Base {
public:
virtual Derived* clone() const {
return new Derived(*this);
}
};
此处,Base
定义了一个名为clone
的纯虚函数,它返回Base *
。在派生实现中,使用返回类型Derived *
覆盖此虚函数。虽然返回类型与基数不同,但这是绝对安全的,因为任何时候你都会写
Base* ptr = /* ... */
Base* clone = ptr->clone();
对clone()
的调用将始终返回指向Base
对象的指针,因为即使它返回Derived*
,该指针也可以隐式转换为Base*
并且操作定义明确。
更一般地说,函数的返回类型从不被视为其签名的一部分。只要返回类型是协变的,您就可以使用任何返回类型覆盖成员函数。
答案 1 :(得分:48)
是。只要它们是covariant,返回类型就可以不同。 C ++标准就像这样描述(§10.3/ 5):
重写函数的返回类型应与被覆盖函数的返回类型相同,或者协变与函数类相同。如果函数
D::f
覆盖函数B::f
,则如果满足以下条件,则函数的返回类型是协变的:
- 都指向类或指向类 98)
的引用- 返回类型
B::f
中的类与返回类型D::f
中的类相同,或者是返回类型中类的明确直接或间接基类D::f
D
可以访问D::f
- 指针或引用具有相同的cv限定,并且返回类型
B::f
中的类类型具有与返回类型{{中的类类型相同的cv-qualification或更少的cv-qualification 1}}。
脚注98指出“不允许使用类的多级指针或对类的多级指针的引用。”
简而言之,如果D
是B
的子类型,则D
中函数的返回类型必须是{{1}中函数的返回类型的子类型。 1}}。最常见的示例是返回类型本身基于B
和D
,但它们不一定是。{考虑一下,我们有两个不同的类型层次结构:
B
这可行的原因是因为struct Base { /* ... */ };
struct Derived: public Base { /* ... */ };
struct B {
virtual Base* func() { return new Base; }
virtual ~B() { }
};
struct D: public B {
Derived* func() { return new Derived; }
};
int main() {
B* b = new D;
Base* base = b->func();
delete base;
delete b;
}
的任何调用者都期望func
指针。任何Base
指针都可以。因此,如果Base
承诺始终返回D::func
指针,那么它将始终满足祖先类所规定的合同,因为任何Derived
指针都可以隐式转换为{{1指针。因此,呼叫者将始终得到他们期望的结果。
除了允许返回类型变化外,某些语言还允许覆盖函数的参数类型也不同。当他们这样做时,他们通常需要逆变。也就是说,如果Derived
接受Base
,则B::f
将被允许接受Derived*
。允许后代在他们接受的内容中更宽松,并且在他们返回的内容中更严格。 C ++不允许参数类型的逆转。如果更改参数类型,C ++会将其视为一个全新的函数,因此您开始进行重载和隐藏。有关此主题的更多信息,请参阅维基百科中的Covariance and contravariance (computer science)。
答案 2 :(得分:2)
虚函数的派生类实现可以有Covariant Return Type。