静态选择功能和虚拟功能

时间:2018-09-20 10:38:51

标签: c++ language-lawyer virtual-functions static-typing covariant-return-types

最近我看过这个C ++标准段落(http://eel.is/c++draft/expr.post#expr.call-5):

  

如果postfix-expression指定一个析构函数,则函数调用表达式的类型为void;否则为false。否则,即使实际调用的函数类型不同,函数调用表达式的类型也就是静态选择的函数的返回类型(即忽略虚拟关键字)。此返回类型应为对象类型,引用类型或cv void。

我不太了解这部分:

  

即使实际调用的函数类型不同,函数调用表达式的类型也是静态选择的函数的返回类型(即忽略virtual关键字)。

  1. 这里静态选择的功能是什么?
  2. 如何静态选择虚拟功能?我一直认为它是在运行时选择的。
  3.   

    即使实际调用的函数类型不同。

调用表达式实际上如何调用所选类型的函数?

2 个答案:

答案 0 :(得分:7)

虚拟函数可以具有协变返回类型,

如此

struct Base
{
    virtual ~Base() = default;
    virtual Base* Clone() const { return new Base(*this); }
};

struct Derived : Base
{
    // covariant return type:
    Derived* Clone() const override { return new Derived(*this); }
};

然后

Derived d;

Base& b = d;

auto* clonePtr = b.Clone(); // `auto` is `Base`, even if `Derived::Clone` is called.
                         // runtime type of `clonePtr` is `Derived`
std::unique_ptr<Base> clone(clonePtr); // Done in 2 steps for explanation

答案 1 :(得分:3)

首先,一个例子来说明。

struct B { 
  virtual B* f() { return this; }
};

struct D : B { 
  D* f() override { return this; }
};

void bar(B*) {}
void bar(D*) {}

int main() {
  D d;
  B& b = d;
  bar(b.f()); // calls `bar(B*)`
}

在此,后缀表达式b.f指定一个函数。它是B::f,返回类型为B*。即使覆盖f时,指定的返回类型也是协变(D*)。实际的调用(据说)在运行时已解决的事实并不会改变我们静态选择函数的 identity 的事实。当还涉及重载时,这才是适当的。相同的函数名称可以指定两个或多个函数,而过载解析是(静态地)选择要调用的过载。可以在派生类中重写该重载,但是其标识再次是静态的。