通过C++对协变返回类型的支持,您可以编写以下内容:
class Base {};
class Derived : public Base {};
...
class A {
public:
A(Base* b) : b_(b) {}
virtual Base* Method() { return b_; }
private:
Base* b_;
}
class B : public A {
public:
B(Derived* b) : A(b) {}
// Return `Derived*` type so callers can access functionality specific to
// `Derived` (i.e., not in `Base`).
Derived* Method() override {
static_assert(std::is_base_of_v<Base, Derived>);
// Need to call `A::Method()` since `b_` is private.
// Alternatively, we can make `b_` protected and access it directly.
return dynamic_cast<Derived*>(A::Method());
}
}
似乎在大多数使用协变返回类型的情况下,派生类的方法(上面的B::Method()
(只会进行动态强制转换并返回较窄的指针类型。它不会做任何其他事情。
考虑到这一假设,是否通常不对Method()
使用虚拟调度(即删除virtual
和overridden
关键字(来提高性能更好毕竟,任何在A*
类型上操作的泛型代码都必须使用Base*
类型来存储A::Method()
的返回值(即使指针指向的对象的实际类型是Derived
(,但只要Base
正确使用虚拟调度,那么无论是Base
的方法还是Derived
的方法,都会在Base*
上调用正确的方法。
在大多数使用协变返回类型的情况下,派生类的方法(上面的B::method(((只会进行动态强制转换并返回较窄的指针类型。它不会做任何其他事情。
我对此不太确定。
这两个功能有两个不同的用途:
virtual
方法允许根据调用程序的运行时类型在运行时选择要执行的代码- 返回类型协方差利用类型系统来进一步约束返回类型;最小API";满足CCD_ 14给出的条件。这是编译时检查
我强烈认为B::Method
根本不应该以其当前的形式存在,让我们采用以下层次结构:
struct Base{
virtual ~Base()=default;
};
struct D1:Base{};
struct D2:Base{};
struct A {
virtual Base* Method() { return new D1{}; }
};
struct B1 : A {
D1* Method() override {
return dynamic_cast<D1*>(A::Method());
}
};
struct B2 : A {
D2* Method() override {
return dynamic_cast<D2*>(A::Method());
}
};
这种用法:
#include <cassert>
int main()
{
B1 b1;
B2 b2;
A* a = &b1;
assert(a->Method()!=nullptr);
a = &b2;
assert(a->Method()==nullptr);
}
这似乎有点奇怪,你会如何编写这个A::Method
的文档?它可以用来做什么?也许是过滤器?
我认为更常见的例子,至少从我所看到的来看,是派生方法自己产生派生结果。以Request
、Response
和virtual Response* Request::process
方法为例。特殊请求可能会得到特殊回复。
为了回答您的问题:如果删除virtual
,您将失去虚拟调度,如果用户代码可以使用静态多态性,那么这是肯定的。不过,根据我的经验,如果在某些Foo
中开始用T
替换Base*
类型的成员变量,那么处理这些现在异构的Foo<T>
的存储所需的模板化代码往往会传播得相当快。为了什么,只为了表演?当然,您之所以考虑这一点,只是因为您测量了代码,并且它是应用程序中的一个明显瓶颈。