Пытаться понять динамическое связывание и виртуальные функции

Учитывая коды ниже:

class Base
{
public:
virtual void f()
{
std::cout << "virtual Base::f()\n";
}
};

class D1 : public Base
{
public:
virtual void f()
{
std::cout << "virtual D1::f()\n";
}
};

int main()
{
D1 d1;
Base *bp = &d1;
bp->f();
return 0;
}

Выход был именно то, что я ожидал:

virtual D1::f()
Press <RETURN> to close this window...

Но однажды я удалил virtual void f() от class BaseКомпилятор пожаловался, что:

error: 'class Base' has no member named 'f'

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

-1

Решение

Вы вызываете виртуальные функции-члены через указатель на Base, Это означает, что вы можете вызывать только те методы, которые существуют в Base учебный класс. Вы не можете просто добавлять методы к типу динамически.

2

Другие решения

Хотя немного поздно, как ответ, прямая цитата из C ++ Primer о том, как разрешаются вызовы функций по отношению к наследованию. Ваш код не выполняется при поиске имени (шаг 2 ниже), что делается статически.

Понимание того, как решаются вызовы функций, крайне важно для
понимание наследования в C ++. Учитывая вызов p-> mem () (или
obj.mem ()), выполняются следующие четыре шага:

  1. Сначала определите статический тип p (или obj). Потому что мы звоним
    член, этот тип должен быть типом класса.

  2. Ищите mem в классе, который соответствует статическому типу p (или obj). Если mem не найден, посмотрите в прямой базовый класс и
    продолжить цепочку классов до тех пор, пока не будет найдена mem или последний класс
    ищется. Если mem не найден в классе или в его базе
    классы, то вызов не будет компилироваться.

  3. Как только mem найден, выполните обычную проверку типов (§6.1, стр. 203), чтобы проверить, является ли этот вызов допустимым с учетом найденного определения.

  4. Предполагая, что вызов допустим, компилятор генерирует код, который варьируется в зависимости от того, является ли вызов виртуальным или нет:

    — Если мем виртуальный и звонок сделан по ссылке или
    указатель, затем компилятор генерирует код для определения во время выполнения
    какую версию запустить на основе динамического типа объекта.

    — В противном случае, если функция не виртуальная, или если вызов
    объект (не ссылка или указатель), компилятор генерирует нормальный
    вызов функции.

1

По вопросам рекламы [email protected]