Здравствуйте OlegT, Вы писали:
G>>Есть два класса базовый и дочерний. В базовом задана виртуальная функция, в дочернем она переопределяется. Проблема в следующем в конструкторе базового класса я дергую за виртуальную функцию и вызывается функция базового класса, можно ли это как то вылечить, что бы конструкторе базового класса вызывалась реализация метода дочернего?
OT>Конечно же, нет. Но я думаю, стоит объяснить "почему" (хотелось бы верить, что это прояснит многие похожие случаи). Как сказал, по-моему, Д'Аламбер "знание нескольких базовых фактов освобождает нас от запоминания множества следствий". OT>Поехали ...
OT> ...
OT>То есть, по-сути при конструировании объекта самого верхнего класса вызываются все конструкторы начиная с низа иерархии OT>и перед тем как войти в очередной конструктор класса Derived_i указателю на таблицу вирт. функций этого объекта присваивается указатель на таблицу вирт. ф-ций класса Derived_i. А внутри этого констр. происходит вызов, скажем, i-й виртуальной функции как (*(this)[i])( parameters ) . OT>В деструкторах же — все с точностью доо наоборот.
OT>Н-да, получилось длинновато, но, надеюсь, понятно. :) (И еще одно, тут приведена только общая схема, возможно с небольшими погрешностями ... но принцип работы она отражает).
Получилось действительно длинновато. А теперь загляни в код вызова виртуальной функции класса непосредственно из его конструктора или деструктора, сгенерированный, например, VC6, и ты обнаружишь, что все написанное тобой в этом случае не имеет никакого отношения к действительности.
Стандарт языка С++ требует, чтобы при вызове их конструктора/деструктора виртуальные функции вели себя так, как будто они являются невиртуальными. При вызове непосредственно из конструктра/деструкора именно так (т.е. невиртуально) и производит вызовы этих функций VC6 (да и другие компиляторы). Т.е. вызов статически направляется в точку входа функции и никакие таблицы виртуальных функций в процессе выполнения такого вызова никоим образом не участвуют.
При выполнении опосредованного вызова виртуальной функции из конструктора/деструктора (через посредство другой функции) все действительно происходит так, как ты описал. Конструкторы/деструкоры действительно подменяют указатель на VMT в экземпляре класса. Это делается для того, чтобы удовлетворить вышеупомянутому требованию стандарта С++ и при опосредованном вызове.
Твое объяснение является на самом деле ответом на вопрос "как?" ("Как компилятор ухитряется удовлетворить этому требованию стандарта языка С++ при опосредованном вызове?"), а не на вопрос "почему?". Причем твой ответ на вопрос "как?" является правильным только для ограниченного набора компиляторов. Какой-нибудь другой компилятор может реализовать эту функциональность по-другому.
А правильный ответ на вопрос "почему?" существенно проще и короче: потому что этого требует стандарт языка С++.