Виртуальные звонки в наследство - PullRequest
0 голосов
/ 05 апреля 2011

Как узнать, разрешен ли вызов функции во время компиляции или во время выполнения из какого-либо класса?

Например - в следующем классе From Derived при вызове show() будет ли он разрешен во время выполнения?

#include <iostream>
using std::ostream;

class Base 
{
public:
    virtual void show() {

         show(); //Call derived class 'show()'
    }
};

class Derived : public Base {

public:

    void show() {

         show(); //Call to itself, Would this call be resolved at run-time?
    }
};

ostream& operator <<(ostream &os, Base &obj)
{

    obj.Base::show();
    return os;
}

int main()
{
    Derived D;

    cout << D << endl;
}

Ответы [ 3 ]

2 голосов
/ 05 апреля 2011

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

В вашем примере вызовы show () выполняются через указатель this и впоследствииони будут решены во время выполнения.Учтите, что всегда может быть класс, даже дальше по цепочке наследования, который реализует show ().

Явно квалифицированный вызов obj.Base :: show () явно разрешается во время компиляции.

0 голосов
/ 05 апреля 2011

Чтобы ответить на ваш вопрос, в вашем коде obj.Base :: show () разрешается во время компиляции из-за явного вызова функции Base.Если вы хотите решить эту проблему во время выполнения, вы можете использовать указатель на базу и передать ей указатель на производное.

Например:

ostream& operator <<(ostream &os, Base *obj)
{    
    obj->show();
    return os;
}

int main()
{
    Derived D;    
    cout << &D << endl;
}

Я не уверенчто ты пытаешься сделать.Из вашего кода кажется, что вы хотите вызвать производную (полиморфную, разрешенную во время выполнения) из функции базового класса 'show ()'.В этом нет необходимости, поскольку производная версия вызывается автоматически, потому что она виртуальная.

0 голосов
/ 05 апреля 2011

Всякий раз, когда компилятор может выяснить, какую перегрузку вашей функции вызывать, он это сделает.Гарантированно будет возможность сделать это, когда

  • имеет полный тип объекта (например, Foo foo; foo.bar();)
  • , вы сообщаете ему, какую перегрузку вызывать (например, Foo foo; foo.Bar::bar();)

но это может быть в состоянии сделать это в тех случаях, когда это менее очевидно - т.е. если он может выяснить, что "этот указатель на Foo действительно всегда указывает наBar».Это называется devirtualization и является частью ночных очков, которые есть у оптимизирующего компилятора.В зависимости от вашего компилятора и от вашего реального кода, может быть возможно выполнить эту оптимизацию - и вызывать вашу функцию напрямую, без прохождения через vtable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...