Re[2]: Проясните еще раз с pure virtual call
От: Павел Кузнецов  
Дата: 02.09.03 12:11
Оценка: :)
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ> Теоретицки, "все разрушается в том же порядке, в каком создавалось",


Скорее, в обратном
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Проясните еще раз с pure virtual call
От: Дмитрий Наумов  
Дата: 02.09.03 10:08
Оценка:
class B
{
public:
  void DoSomethingBeforeExit() { OnClose(); }
  virtual void OnClose() { ... }
};

class D
{
public:
  ~D() { DoSomethingBeforeExit(); }
  virtual void OnClose() { ... }
};


Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?
Спасибо за то что ответили на юзаный-переюзанный вопрос.
Re: Проясните еще раз с pure virtual call
От: Зверёк Харьковский  
Дата: 02.09.03 10:16
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:


ДН>
ДН>class B
ДН>{
ДН>public:
ДН>  void DoSomethingBeforeExit() { OnClose(); }
ДН>  virtual void OnClose() { ... }
ДН>};

ДН>class D
ДН>{
ДН>public:
ДН>  ~D() { DoSomethingBeforeExit(); }
ДН>  virtual void OnClose() { ... }
ДН>};
ДН>


ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?

ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.

Теоретицки, "все разрушается в том же порядке, в каком создавалось", т.е. таблица вирт. функций, будучи создана ДО входа в консруктор, будет. видимо, разрушена ПОСЛЕ выхода из деструктора.
FAQ — це мiй ай-кью!
Re[2]: Проясните еще раз с pure virtual call
От: Дмитрий Наумов  
Дата: 02.09.03 10:49
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Теоретицки, "все разрушается в том же порядке, в каком создавалось", т.е. таблица вирт. функций, будучи создана ДО входа в консруктор, будет. видимо, разрушена ПОСЛЕ выхода из деструктора.


Хотелось бы знать наверняка.
Re[3]: Проясните еще раз с pure virtual call
От: MT  
Дата: 02.09.03 11:02
Оценка:
ДН>Хотелось бы знать наверняка.

Можно попробовать "метод тыка" — откомпилируй с дебаг выводами, и все увидишь.
Быстрее, лучше, дешевле — выбери любые два.
(Старая инженерная поговорка)
Re: Проясните еще раз с pure virtual call
От: Кодт Россия  
Дата: 02.09.03 11:06
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?


Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции.
При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса.
При входе в деструктор — то же самое.
Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt).
Деструирование, соответственно, наоборот.

В конструкторе и деструкторе вызовы методов статические (без использования VMT). Это позволяет, в частности, объявлять абстрактный класс с определенными методами:
class AbstractClass
{
public:
  AbstractClass();
  virtual void method() = 0;
};

AbstractClass::method()
{
  cout << "hello";
}

AbstractClass::AbstractClass()
{
  method();
}

Однако можно форсировать динамический вызов (опосредовав его):
class AbstractClass
{
public:
  AbstractClass() { call_method(); }
  virtual void method() = 0;
  void call_method() { method(); }
};

что приведет к фейерверку.
Перекуём баги на фичи!
Re: Проясните еще раз с pure virtual call
От: grs Россия  
Дата: 02.09.03 11:13
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:


ДН>
ДН>class B
ДН>{
ДН>public:
ДН>  void DoSomethingBeforeExit() { OnClose(); }
ДН>  virtual void OnClose() { ... }
ДН>};

ДН>class D
ДН>{
ДН>public:
ДН>  ~D() { DoSomethingBeforeExit(); }
ДН>  virtual void OnClose() { ... }
ДН>};
ДН>


ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?

ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.

В принципе твой код корректен. Деструкторы для данного класса вызываются перед его уничтожением.
Я другого не понял. А причем здесь pure virtual call?
Re[2]: Проясните еще раз с pure virtual call
От: Дмитрий Наумов  
Дата: 02.09.03 11:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции.

К>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса.
К>При входе в деструктор — то же самое.
К>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt).
К>Деструирование, соответственно, наоборот.

Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.
Re: Проясните еще раз с pure virtual call
От: e-Xecutor Россия  
Дата: 02.09.03 12:08
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:


ДН>
ДН>class B
ДН>{
ДН>public:
ДН>  void DoSomethingBeforeExit() { OnClose(); }
ДН>  virtual void OnClose() { ... }
ДН>};

ДН>class D
ДН>{
ДН>public:
ДН>  ~D() { DoSomethingBeforeExit(); }
ДН>  virtual void OnClose() { ... }
ДН>};
ДН>


ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?

ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.

Вообщем-то код слегонца косячный, наследование забыл
И собственно 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(). Вы хотите сказать, что происходит что-то иное?
Re[2]: Проясните еще раз с pure virtual call
От: Дмитрий Наумов  
Дата: 02.09.03 12:28
Оценка:
Здравствуйте, e-Xecutor, Вы писали:

EX>Вообщем-то код слегонца косячный, наследование забыл


Угу. Наследование забыл.

EX>И собственно pure virtual забыл.


А это нет. Я не говорил, что OnClose есть pure virtual. Я говорил про ситуацию, в которой вызывается функция-заглушка компилятора. Это может произойти как при косвенном вызове pure virtual member, так и при вызове просто virtual member, но в "неудачное" время.
Re[3]: Проясните еще раз с pure virtual call
От: jazzer Россия Skype: enerjazzer
Дата: 02.09.03 12:38
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

ДН>Я говорил про ситуацию, в которой вызывается функция-заглушка компилятора. Это может произойти как при косвенном вызове pure virtual member, так и при вызове просто virtual member, но в "неудачное" время.


это как?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

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, но в "неудачное" время.


Это "неудачное" время натупает при неопределенном поведении. На пример хотелось бы посмотреть.
Re: Проясните еще раз с pure virtual call
От: Дмитрий Наумов  
Дата: 02.09.03 12:53
Оценка:
Прошу всех извинить, там действительно члены объявлены pure virtual, тогда все ясно.
Re: Проясните еще раз с pure virtual call
От: Андрей Тарасевич Беларусь  
Дата: 02.09.03 17:57
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

ДН>
ДН>class B
ДН>{
ДН>public:
ДН>  void DoSomethingBeforeExit() { OnClose(); }
ДН>  virtual void OnClose() { ... }
ДН>};

ДН>class D
ДН>{
ДН>public:
ДН>  ~D() { DoSomethingBeforeExit(); }
ДН>  virtual void OnClose() { ... }
ДН>};
ДН>


ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта?


Валидно, разумеется. Только надо помнить, что при прямом или косвенном вызове из конструктора/деструктора выбор конкретной функции будет делаться в соответствии со статическим типом объекта.

ДН>Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?


Это не более общий вопрос. Это более частный вопрос. В С++ нет никакой "таблицы виртуальных функций". В С++ есть понятия статического и динамического типов объектов и все подобные спецификации формулируются через них.

А "таблицы виртуальных функций" (VMT) — это частные особенности конкретных реализаций. VMT не разрушаются и не заполняются заглушками. В процессе конструкции/деструкции объекта выполняется коррекция указателя на VMT так, чтобы текущая указуемая VMT всегда соотвествовала "текущему" статическому типу объекта. Проще всего это сделать именно при входе в конструктор/деструктор.

P.S. В заголовке у тебя идет речь о pure virtual call. Что-то я не увидел в твоем вопросе ничего специфичного именно pure virtual call.
Best regards,
Андрей Тарасевич
Re[3]: Проясните еще раз с pure virtual call
От: Андрей Тарасевич Беларусь  
Дата: 02.09.03 21:25
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

К>>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции.

К>>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса.
К>>При входе в деструктор — то же самое.
К>>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt).
К>>Деструирование, соответственно, наоборот.

ДН>Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного

класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.

Откуда ты взял эти заглушки? Нет никаких заглушек. Во время выполнения деструктора производного класса, указатель VMT удалаемого объекта указывает на полноценную VMT производного класса. При переходе к выполнению деструктора базового класса этот указатель будет переставлен на VMT базового класса (тоже полноценную). Никаких "заглушек".
Best regards,
Андрей Тарасевич
Re[4]: Проясните еще раз с pure virtual call
От: jazzer Россия Skype: enerjazzer
Дата: 03.09.03 07:12
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Здравствуйте, Дмитрий Наумов, Вы писали:


К>>>Сами таблицы (будучи глобальными данными) не разрушаются. Они забиваются заглушками еще на стадии компиляции.

К>>>При входе в конструктор члену-указателю на таблицу (vfptr) присваивается адрес таблицы данного класса.
К>>>При входе в деструктор — то же самое.
К>>>Конструирование объекта происходит по нарастающей: сначала — конструктор предка (vfptr = &parent_vmt), затем конструктор данного класса (vfptr = &my_vmt).
К>>>Деструирование, соответственно, наоборот.

ДН>>Ок, но ведь в моем примере, я пытаюсь косвенно вызвать виртуальный метод еще находясь в деструкторе производного

АТ>класса. Судя по симптомам в этом время vfptr уже настроен на заглушки, а не на реальную таблицу вирт. функций.

АТ>Откуда ты взял эти заглушки? Нет никаких заглушек. Во время выполнения деструктора производного класса, указатель VMT удалаемого объекта указывает на полноценную VMT производного класса. При переходе к выполнению деструктора базового класса этот указатель будет переставлен на VMT базового класса (тоже полноценную). Никаких "заглушек".


Наверное, имеются в виду заглушки для чисто виртуальных функций, которые инициируют обвал программы с соответствующей диагностикой...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Проясните еще раз с pure virtual call
От: Romanch  
Дата: 03.09.03 07:24
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:


ДН>
ДН>class B
ДН>{
ДН>public:
ДН>  void DoSomethingBeforeExit() { OnClose(); }
ДН>  virtual void OnClose() { ... }
ДН>};

ДН>class D
ДН>{
ДН>public:
ДН>  ~D() { DoSomethingBeforeExit(); }
ДН>  virtual void OnClose() { ... }
ДН>};
ДН>


ДН>Итак, теперь словами. Валидно ли вызвать виртуальную функцию (косвенно или напрямую) из деструктора дочернего объекта? Или более общий вопрос — когда разрушается (заполняется заглушками) таблица вирт. функций? При входе в деструктор?

ДН>Спасибо за то что ответили на юзаный-переюзанный вопрос.

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).

Дима, догадайся с 3-х раз, откуда сия цитата ?
Re[3]: Проясните еще раз с pure virtual call
От: Зверёк Харьковский  
Дата: 03.09.03 12:22
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, Зверёк Харьковский, Вы писали:


ЗХ>> Теоретицки, "все разрушается в том же порядке, в каком создавалось",


ПК>Скорее, в обратном


Ну да, ну да, это-то я и хотел сказать
FAQ — це мiй ай-кью!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.