Здравствуйте Grenal, Вы писали:
G>Есть два класса базовый и дочерний. В базовом задана виртуальная функция, в дочернем она переопределяется. Проблема в следующем в конструкторе базового класса я дергую за виртуальную функцию и вызывается функция базового класса, можно ли это как то вылечить, что бы конструкторе базового класса вызывалась реализация метода дочернего?
Конечно же, нет. Но я думаю, стоит объяснить "почему" (хотелось бы верить, что это прояснит многие похожие случаи). Как сказал, по-моему, Д'Аламбер "знание нескольких базовых фактов освобождает нас от запоминания множества следствий".
Поехали ...
class Base
{
public:
Base():mBase(1) { f(); };
virtual void f() {};
virtual void g() {};
long mBase;
};
class Derived: public Base
{
public:
Derived():mDerived(2) { g(); };
virtual void f() {};
virtual void g() {};
long mDerived
}
int main()
{
...
Derived derived_Obj;
...
}
Что же происходит в строчке " Derived derived_Obj; "?
Прежде всего, примем к сведению, что к этому моменту уже созданы таблицы вирт. функций для классов Base и Derived. Обозначим указатели на них vtBase_ptr и vtDerived_ptr соответственно и допустим, что они находятся в начале каждого объекта ([объект в памяти] = [указ. на табл. вирт. ф-ций][данные] (если, конечно, у класса есть вирт. ф-ции)).
То есть, в нашем случае [derived_Obj] = [vtPtr][long][long].
Virtual Table класса Base:
vtBase_ptr[0] = указатель на функцию f класса Base (1)
vtBase_ptr[1] = указатель на функцию g класса Base (2)
Virtual Table класса Derived:
vtDerived_ptr[0] = указатель на функцию f класса Derived (3)
vtDerived_ptr[1] = указатель на функцию g класса Derived (4)
Итак ...
— Выделяется память(в стеке) размером [vtPtr]+[mBase]+[mDerived] = 12 байт и указатель на нее присваивается this'у
— *(this + 4 байта) = 1 { mBase = 1 }
— *(this) = vtBase_ptr { vtPtr = vtBase_ptr }
— вызываем конструктор класса Base
— вызываем функцию (*this)[0] { (vtBase_ptr[0])() , f() класса Base, см. (1) }
— выходим из конструктора класса Base
— *(this + 8 байт) = 2 { mDerived = 2 }
— *(this) = vtDerivedPtr { vtPtr = vtDerived_ptr }
— вызываем конструктор класса Derived
— вызываем функцию (*this)[1] { (vtDerived_ptr[1])() , g() класса Derived см. (4) }
— выходим из конструктора класса Derived
То есть, по-сути при конструировании объекта самого верхнего класса вызываются все конструкторы начиная с низа иерархии
и перед тем как войти в очередной конструктор класса Derived_i указателю на таблицу вирт. функций этого объекта присваивается указатель на таблицу вирт. ф-ций класса Derived_i. А внутри этого констр. происходит вызов, скажем, i-й виртуальной функции как (*(this)[i])( parameters ) .
В деструкторах же — все с точностью доо наоборот.
Н-да, получилось длинновато, но, надеюсь, понятно.

(И еще одно, тут приведена только общая схема, возможно с небольшими погрешностями ... но принцип работы она отражает).