Вызов виртуальных функций внутри функций-членов - PullRequest
1 голос
/ 02 марта 2010

Я читаю Мышление на С ++ Брюса Экеля. В главе 15 (том 1) под заголовком « Поведение виртуальных функций внутри конструктора » он выходит

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

Здесь Брюс пытается объяснить, что когда вы вызываете виртуальную функцию внутри конструктора объекта, полиморфизм не проявляется, то есть функция текущего класса будет вызываться только и не будет какой-либо другой производной версией класса этой функции. Это верно, и я могу это понять, так как конструктор для класса не будет знать заранее, работает ли он для него или для создания какого-либо другого объекта. Более того, если это так, то это будет вызывать функции для частично созданного объекта, что губительно.

Хотя моя путаница внезапно возникла из-за первого предложения, в котором он заявляет об обычной функции-члене, где он говорит, что виртуальный вызов будет разрешен во время выполнения. Но подождите, внутри любой функции-члена класса, когда вы вызываете другую функцию (виртуальную или не виртуальную), будет вызываться только ее собственная версия класса, верно? Э.Г.

class A
{
    virtual void add() { subadd(); }
    virtual subadd() { std::cout << "A::subadd()\n"; }
};

class B : public A
{
    void add() { subadd(); }
    void subadd() { std::cout << "B::subadd()\n"; }
};

В приведенном выше коде, в A::add(), когда сделан вызов на subadd(), он будет всегда вызывать A::subadd(), и то же самое верно и для B, верно? Так что он имеет в виду, когда «виртуальный вызов разрешается во время выполнения, потому что объект не может знать, принадлежит ли он классу, в котором находится функция-член, или некоторому классу, производному от него»? *

Он объясняет это относительно вызова через указатель базового класса ? (Я действительно так подозреваю). В этом случае он не должен писать «Внутри обычной функции-члена»; насколько я понимаю, любой вызов функции-члена из другой функции-члена того же класса не является полиморфным, пожалуйста, исправьте меня, если я ошибаюсь.

Ответы [ 3 ]

6 голосов
/ 02 марта 2010

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

class C : public B
{
public:
    // Not overriding B::add.
    void subadd() { std::cout << "C::subadd\n"; }
};

A *a = new C;
a->add();

Это динамически вызывает B::add, что в свою очередь динамически вызывает C::subadd. Статический вызов B::subadd был бы неправильным, поскольку динамический тип C и C переопределяют функцию.

В вашем примере дублирование A::add для B::add не нужно - оба будут вызывать subadd полиморфно независимо от динамического типа объекта.

3 голосов
/ 02 марта 2010

когда вы вызываете другую функцию (виртуальную или не виртуальную), вызывается только ее собственная версия класса, верно?

Извините, не так. Конструктор является исключением. В противном случае вы имеете дело с полностью сконструированным объектом, для которого существует полный полиморфизм. В последующем примере (если B наследует от A) то, что называется B::subadd() (просто возьмите код для тест-драйва: это действительно лучший способ узнать, как работает язык программирования).

1 голос
/ 02 марта 2010

Вызов subadd(); в ваших примерах действительно является вызовом this->subadd();. В A::add() тип this равен A*, но this может указывать на объект C (при условии, что C также происходит от A). При компиляции A::add() компилятор не может знать, какие виртуальные функции переопределены в class C. Вызов this->subadd(); в A::add() может фактически вызвать C::subadd(). Таким образом, у компилятора нет другого выбора, кроме как ввести виртуальный вызов, который должен быть разрешен во время выполнения, когда он знает, куда указывает this->.

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