class B
{
public:
void DoSomethingBeforeExit() { OnClose(); }
virtual void OnClose() { ... }
};
class D
{
public:
~D() { DoSomethingBeforeExit(); }
virtual void OnClose() { ... }
};
Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?
Спасибо за то что ответили на юзаный-переюзанный вопрос.
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор? ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.
Теоретицки, "все разрушается в том же порядке, в каком создавалось", т.е. таблица вирт. функций, будучи создана ДО входа в консруктор, будет. видимо, разрушена ПОСЛЕ выхода из деструктора.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Теоретицки, "все разрушается в том же порядке, в каком создавалось", т.е. таблица вирт. функций, будучи создана ДО входа в консруктор, будет. видимо, разрушена ПОСЛЕ выхода из деструктора.
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?
Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции.
При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса.
При входе в деструктор — то же самое.
Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt).
Деструирование, соответственно, наоборот.
В конструкторе и деструкторе вызовы методов статические (без использования VMT). Это позволяет, в частности, объявлять абстрактный класс с определенными методами:
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор? ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.
В принципе твой код корректен. Деструкторы для данного класса вызываются перед его уничтожением.
Я другого не понял. А причем здесь pure virtual call?
Здравствуйте, Кодт, Вы писали:
К>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции. К>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса. К>При входе в деструктор — то же самое. К>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt). К>Деструирование, соответственно, наоборот.
Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор? ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.
Вообщем-то код слегонца косячный, наследование забыл
И собственно pure virtual забыл.
Кстати косвенный вызов от прямого СИЛЬНО отличается.
Ибо косвенный будет таки виртуальным, а прямой вызов
виртуального метода из деструктора на самом деле статический.
Конкретно этот код сработает, но он потенциально опасен.
Если OnClose таки будет pure vurtual, и схема будет, скажем, такой:
class Base{
public:
void DoSomethingBeforeExit(){OnClose();}
virtual void OnClose()=0;
};
class Child1:public Base{
public:
~Child(){DoSomethingBeforeExit();}
};
class Child2:public Child1{
public:
void OnClose(){/* do something*/}
};
то будет бяка
Re[3]: Проясните еще раз с pure virtual call
От:
Аноним
Дата:
02.09.03 12:16
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.
Что-то я не пойму проблему. В Вашем примере (если подразумевать в нем наследование D от B) из D::~D() должна вызываться D::OnClose(). Вы хотите сказать, что происходит что-то иное?
Здравствуйте, e-Xecutor, Вы писали:
EX>Вообщем-то код слегонца косячный, наследование забыл
Угу. Наследование забыл.
EX>И собственно pure virtual забыл.
А это нет. Я не говорил, что OnClose есть pure virtual. Я говорил про ситуацию, в которой вызывается функция-заглушка компилятора. Это может произойти как при косвенном вызове pure virtual member, так и при вызове просто virtual member, но в "неудачное" время.
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>Я говорил про ситуацию, в которой вызывается функция-заглушка компилятора. Это может произойти как при косвенном вызове pure virtual member, так и при вызове просто virtual member, но в "неудачное" время.
You will always get what you always got
If you always do what you always did
Re[3]: Проясните еще раз с pure virtual call
От:
Аноним
Дата:
02.09.03 12:46
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>А это нет. Я не говорил, что OnClose есть pure virtual. Я говорил про ситуацию, в которой вызывается функция-заглушка компилятора. Это может произойти как при косвенном вызове pure virtual member, так и при вызове просто virtual member, но в "неудачное" время.
Это "неудачное" время натупает при неопределенном поведении. На пример хотелось бы посмотреть.
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта?
Валидно, разумеется. Только надо помнить, что при прямом или косвенном вызове из конструктора/деструктора выбор конкретной функции будет делаться в соответствии со статическим типом объекта.
ДН>Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?
Это не более общий вопрос. Это более частный вопрос. В С++ нет никакой "таблицы виртуальных функций". В С++ есть понятия статического и динамического типов объектов и все подобные спецификации формулируются через них.
А "таблицы виртуальных функций" (VMT) — это частные особенности конкретных реализаций. VMT не разрушаются и не заполняются заглушками. В процессе конструкции/деструкции объекта выполняется коррекция указателя на VMT так, чтобы текущая указуемая VMT всегда соотвествовала "текущему" статическому типу объекта. Проще всего это сделать именно при входе в конструктор/деструктор.
P.S. В заголовке у тебя идет речь о pure virtual call. Что-то я не увидел в твоем вопросе ничего специфичного именно pure virtual call.
Здравствуйте, Дмитрий Наумов, Вы писали:
К>>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции. К>>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса. К>>При входе в деструктор — то же самое. К>>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt). К>>Деструирование, соответственно, наоборот.
ДН>Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного
класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.
Откуда ты взял эти заглушки? Нет никаких заглушек. Во время выполнения деструктора производного класса, указатель VMT удалаемого объекта указывает на полноценную VMT производного класса. При переходе к выполнению деструктора базового класса этот указатель будет переставлен на VMT базового класса (тоже полноценную). Никаких "заглушек".
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Дмитрий Наумов, Вы писали:
К>>>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции. К>>>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса. К>>>При входе в деструктор — то же самое. К>>>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt). К>>>Деструирование, соответственно, наоборот.
ДН>>Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного АТ>класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.
АТ>Откуда ты взял эти заглушки? Нет никаких заглушек. Во время выполнения деструктора производного класса, указатель VMT удалаемого объекта указывает на полноценную VMT производного класса. При переходе к выполнению деструктора базового класса этот указатель будет переставлен на VMT базового класса (тоже полноценную). Никаких "заглушек".
Наверное, имеются в виду заглушки для чисто виртуальных функций, которые инициируют обвал программы с соответствующей диагностикой...
ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор? ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.
12.7.3
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor's own class or in one of its bases, but not a function overriding it in a class derived from the constructor or destructor's class, or overriding it in one of the other base classes of the most derived object (1.8).
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>> Теоретицки, "все разрушается в том же порядке, в каком создавалось",
ПК>Скорее, в обратном