В C ++ совершенно безопасно вызывать виртуальные функции из базового класса - если они не чисты - с некоторыми ограничениями. Тем не менее, вы не должны этого делать. Лучше инициализировать объекты, используя не виртуальные функции, которые явно помечены как такие функции инициализации, используя комментарии и соответствующее имя (например, initialize
). Если он даже объявлен как чисто виртуальный в вызывающем его классе, поведение не определено.
Версия, которая вызывается, является классом, вызывающим ее из конструктора, а не некоторой переопределением в каком-либо производном классе. Это не имеет большого отношения к таблицам виртуальных функций, но больше связано с тем, что переопределение этой функции может принадлежать классу, который еще не инициализирован. Так что это запрещено.
В C # и Java это не проблема, потому что нет такой вещи, как инициализация по умолчанию, которая выполняется непосредственно перед вводом тела конструктора. В C # единственные вещи, которые выполняются вне тела, - это вызов конструкторов базового класса или родственных элементов. Однако в C ++ инициализация, выполняемая для членов производных классов с помощью переопределения этой функции, будет отменена при конструировании этих членов при обработке списка инициализатора конструктора непосредственно перед входом в тело конструкторов производного класса.
Редактировать : Из-за комментария, я думаю, нужно немного разъяснений. Вот (надуманный) пример, давайте предположим, что ему будет позволено вызывать виртуальные устройства, и этот вызов приведет к активации последней переопределенной переменной:
struct base {
base() { init(); }
virtual void init() = 0;
};
struct derived : base {
derived() {
// we would expect str to be "called it", but actually the
// default constructor of it initialized it to an empty string
}
virtual void init() {
// note, str not yet constructed, but we can't know this, because
// we could have called from derived's constructors body too
str = "called it";
}
private:
string str;
};
Эту проблему действительно можно решить, изменив стандарт C ++ и разрешив его - изменив определение конструкторов, время жизни объекта и еще много чего. Должны быть созданы правила, чтобы определить, что означает str = ...;
для еще не построенного объекта. И обратите внимание, как эффект от этого зависит от того, кто позвонил init
. Функция, которую мы получаем, не оправдывает проблем, которые мы должны решить. Поэтому C ++ просто запрещает динамическую диспетчеризацию во время конструирования объекта.