3 回答
TA贡献1862条经验 获得超7个赞
在某些情况下,是的,只要返回类型与原始返回类型协变,派生类使用不同的返回类型覆盖虚拟函数是合法的。例如,考虑以下内容:
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,该函数返回a Base *。在派生的实现中,此虚拟函数使用的返回类型重写Derived *。尽管返回类型与基本类型不同,但这是绝对安全的,因为任何时候您都会编写
Base* ptr = /* ... */
Base* clone = ptr->clone();
调用to clone()始终会返回指向Base对象的指针,因为即使返回a Derived*,该指针也可以隐式转换为a,Base*并且该操作定义明确。
更一般而言,函数的返回类型从不视为其签名的一部分。您可以使用任何返回类型覆盖成员函数,只要返回类型是协变的即可。
TA贡献1744条经验 获得超4个赞
是。只要它们是协变的,返回类型就可以不同。C ++标准对此进行了描述(第10.3 / 5节):
覆盖函数的返回类型应与覆盖函数的返回类型相同或与函数的类协变。如果一个函数D::f覆盖某个函数B::f,则满足以下条件的函数的返回类型将是协变的:
两者都是指向类或指向类98的指针)
返回类型B::f为的类与D::f或返回类型为的类相同,是返回类型为的类的明确的直接或间接基类,D::f并且可以在中访问D
指针或引用都具有相同的cv限定,并且返回类型的类类型D::f具有与等于或小于返回类型的类类型相同的cv限定B::f。
脚注98指出“不允许使用指向类的多级指针或指向类的多级指针”。
简而言之,如果D是的子类型B,则in中的函数的返回类型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;
}
之所以起作用,是因为任何的调用者func都希望有一个Base指针。任何Base指针都可以。因此,如果D::func保证总是返回一个Derived指针,那么它将始终满足祖先类提出的约定,因为任何Derived指针都可以隐式转换为Base指针。因此,呼叫者将始终得到他们所期望的。
除了允许返回类型改变之外,某些语言还允许覆盖函数的参数类型改变。当他们这样做时,它们通常需要保持不变。也就是说,如果B::f接受Derived*,则将D::f允许接受Base*。后代可以放宽接受的条件,严格要求返回的条件。C ++不允许参数类型相反。如果更改参数类型,则C ++会将其视为全新功能,因此您开始陷入重载和隐藏状态。有关此主题的更多信息,请参见Wikipedia中的协方差和逆方差(计算机科学)。
- 3 回答
- 0 关注
- 825 浏览
添加回答
举报