Вы должны никогда не вызывать виртуальные функции в конструкторе.
Виртуальные функции не отправляются так, как вы думаете. Скорее, во время построения динамический тип базового подобъекта, который создается, является базовым типом, и, таким образом, функция отправляется базовой функции (которая в вашем случае является чисто виртуальной).
Просто не делай этого.
(Причина очевидна: при построении производного объекта базовый подобъект обязательно должен быть построен первым, поэтому внешний производный объект даже не существует во время базового построения.)
Изменить: вот еще одно объяснение. Компиляторам вполне разрешено и рекомендуется выполнять виртуальную отправку статически, если они могут это делать. В этом случае уже во время компиляции определяется, какая фактическая функция будет вызвана. Это происходит, когда вы говорите foo()
или this->foo()
в конструкторе Base
или когда вы говорите x.Base::foo()
в каком-либо другом контексте, где Derived x;
- ваш объект. Когда отправка происходит статически, либо реализация Base::foo()
вызывается напрямую, либо вы получаете ошибку компоновщика, если реализации нет.
С другой стороны, если отправка происходит динамически, т. Е. Во время выполнения, то существует вероятность, хотя и необычная, что отправка фактически завершит выбор Base::foo()
в качестве конечной цели. Это не может произойти в «нормальных» условиях, потому что компилятор не позволит вам создать экземпляр класса с чисто виртуальными функциями, и поэтому целью обычной динамической отправки всегда является функция, для которой должна существовать реализация (или, по крайней мере, вы получил бы ошибку компоновщика, если бы вы его не связали).
Но есть еще одна ситуация, о которой идет речь: компилятор решает выполнить отправку во время выполнения по какой-либо причине, и дипатч заканчивается чисто виртуальной функцией. В этом случае ваша программа завершается. Не имеет значения, реализована функция или нет, просто она не имеет записи в иерархии полиморфных классов (воспринимайте это как «нулевой указатель в vtable», отсюда = 0
). Чтобы это произошло, динамический тип объекта должен быть типом абстрактного базового класса, и отправка должна происходить динамически. Первое может быть достигнуто только внутри базового конструктора производного объекта, а второе требует, чтобы вы убедили компилятор не отправлять вызов статически. Вот где проявляется разница между this->foo()
(статический) и Base * p = this; p->foo();
(динамический). (Также сравните это с x.Base::foo()
, который отправляется статически.)
Все это просто следствие реализации и, конечно же, покрывается общим «неопределенным поведением». Если вы хотите убрать что-то из этого, то это то, что динамическая диспетчеризация не может найти чисто виртуальную функцию. И, конечно же, вы никогда не должны вызывать виртуальные функции в конструкторе.
person
Kerrek SB
schedule
02.03.2012
this->foo()
работает, тогда как вызов через приведение не выполняется. - person Agnel Kurian   schedule 06.10.2012