Bob*_*Bob 75 c++ inheritance overriding virtual-functions return-type
是否有可能继承的类实现具有不同返回类型的虚函数(不使用模板作为返回)?
tem*_*def 77
在某些情况下,是的,只要返回类型与原始返回类型协变,派生类使用不同的返回类型覆盖虚函数是合法的.例如,请考虑以下事项:
class Base {
public:
virtual ~Base() {}
virtual Base* clone() const = 0;
};
class Derived: public Base {
public:
virtual Derived* clone() const {
return new Derived(*this);
}
};
Run Code Online (Sandbox Code Playgroud)
在这里,Base
定义了称为纯虚函数clone
返回一个Base *
.在派生实现中,使用返回类型覆盖此虚函数Derived *
.虽然返回类型与基数不同,但这是绝对安全的,因为任何时候你都会写
Base* ptr = /* ... */
Base* clone = ptr->clone();
Run Code Online (Sandbox Code Playgroud)
调用clone()
将始终返回指向Base
对象的指针,因为即使它返回a Derived*
,该指针也可以隐式转换为a Base*
,并且操作是明确定义的.
更一般地,函数的返回类型从不被视为其签名的一部分.只要返回类型是协变的,您就可以使用任何返回类型覆盖成员函数.
Rob*_*edy 50
是.只要它们是协变的,允许返回类型是不同的.C++标准就是这样描述的(§10.3/ 5):
重写函数的返回类型应与重写函数的返回类型相同或与函数类的协变相同.如果函数
D::f
覆盖函数B::f
,则如果满足以下条件,则函数的返回类型是协变的:
- 两者都是类的指针或类的引用98)
- 返回类型中的类与返回类型中
B::f
的类是同一个类,D::f
或者是返回类型中类的明确的直接或间接基类,D::f
并且可以在D
- 指针或引用具有相同的cv限定,并且返回类型中的类类型
D::f
具有与返回类型中的类类型相同的cv-qualification或更少的cv-qualificationB::f
.
脚注98指出"不允许使用类的多级指针或对类的多级指针的引用."
简而言之,如果D
是子B
类型,则函数的返回类型D
需要是函数返回类型的子类型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;
}
Run Code Online (Sandbox Code Playgroud)
这个工作的原因是因为任何调用者func
都期待一个Base
指针.任何Base
指针都可以.因此,如果D::func
promises总是返回一个Derived
指针,那么它将始终满足祖先类所规定的契约,因为任何Derived
指针都可以隐式转换为Base
指针.因此,呼叫者将始终得到他们期望的.
除了允许返回类型变化外,某些语言也允许覆盖函数的参数类型也不同.当他们这样做时,他们通常需要逆变.也就是说,如果B::f
接受a Derived*
,则D::f
允许接受a Base*
.允许后代在他们接受的内容中更宽松,在他们返回的内容中更加严格.C++不允许参数类型的逆转.如果更改参数类型,C++会将其视为一个全新的函数,因此您开始进行重载和隐藏.有关此主题的更多信息,请参阅维基百科中的协方差和逆变(计算机科学).