Статически выбранная функция и виртуальная функция - PullRequest
0 голосов
/ 20 сентября 2018

Недавно я видел этот стандартный абзац C ++ (http://eel.is/c++draft/expr.post#expr.call-5):

Если постфиксное выражение обозначает деструктор, тип выражения вызова функции void; в противном случае типВыражение вызова функции - это тип возврата статически выбранной функции (т. е. игнорирование виртуального ключевого слова), даже если тип фактически вызванной функции отличается. Этот тип возврата должен быть типом объекта, ссылочным типом или cv void.

Я не совсем понимаю эту часть:

тип выражения вызова функции - это тип возврата статически выбранной функции (т. Е. Игнорирование виртуального ключевого слова), даже если тип фактически вызванной функции отличается.

  1. Какая здесь статически выбранная функция?
  2. Как статически выбирается виртуальная функция?всегда думал, что он выбран во время выполнения.
  3. , даже если тип фактически вызванной функции отличается.

Как выражение вызова может фактически вызывать функцию другого типа, который был выбран?

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Во-первых, пример для иллюстрации.

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*).Тот факт, что реальный вызов (предположительно) разрешен во время выполнения, не меняет того факта, что мы статически выбираем идентификатор функции .Это уместно, когда также происходит перегрузка.Одно и то же имя функции может обозначать две или более функций, и это разрешение перегрузки, которое (статически) выбирает, какую перегрузку вызывать.Эта перегрузка может быть переопределена в производном классе, но опять-таки его идентичность является статической.

0 голосов
/ 20 сентября 2018

виртуальные функции могут иметь ковариантный тип возврата,

, поэтому с

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
...