Чеширский кот и изменение наследника до конструктора
От: _Winnie Россия C++.freerun
Дата: 01.09.05 14:00
Оценка:
Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.

template <class Derived>
class Base1
{
public:
  Base()
  {
     static_cast<Derived*>(this)->type_tag = 1;
  }
};

class Derived: public Base<Derived>
{
public:
  int type_tag;
};
Правильно работающая программа — просто частный случай Undefined Behavior
Re: Чеширский кот и изменение наследника до конструктора
От: adontz Грузия http://adontz.wordpress.com/
Дата: 01.09.05 14:11
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.


Ну судя по всему список возможных базовых классов известен заранее.
Так почему бы не заполнять его каким нибудь is_derivied<T,U> ?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re: Чеширский кот и изменение наследника до конструктора
От: Gleb Alexeev  
Дата: 01.09.05 14:13
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.


_W>
_W>template <class Derived>
_W>class Base1
_W>{
_W>public:
_W>  Base()
_W>  {
_W>     static_cast<Derived*>(this)->type_tag = 1;
_W>  }
_W>};

_W>class Derived: public Base<Derived>
_W>{
_W>public:
_W>  int type_tag;
_W>};
_W>


Оригинально. Встречный вопрос: что мы в таком случае выигрываем по сравнению с вынесением type_tag в базовый класс (protected)?
Re: Чеширский кот и изменение наследника до конструктора
От: MaximE Великобритания  
Дата: 01.09.05 14:29
Оценка:
_Winnie wrote:

> Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.


На практике это, скорее всего, будет работать, но зачем?

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re: Чеширский кот и изменение наследника до конструктора
От: Аноним  
Дата: 01.09.05 18:10
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.


_W>
_W>template <class Derived>
_W>class Base1
_W>{
_W>public:
_W>  Base()
_W>  {
_W>     static_cast<Derived*>(this)->type_tag = 1;
_W>  }
_W>};

_W>class Derived: public Base<Derived>
_W>{
_W>public:
_W>  int type_tag;
_W>};
_W>


охохо. интересно, но вот только придётся присоединиться к "толпе" и сказать: "ну и зачем?"
Re: Чеширский кот и изменение наследника до конструктора
От: crable США  
Дата: 02.09.05 05:18
Оценка:
_W>Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.

_W>
_W>template <class Derived>
_W>class Base1
_W>{
_W>public:
_W>  Base()
_W>  {
_W>     static_cast<Derived*>(this)->type_tag = 1;
_W>  }
_W>};

_W>class Derived: public Base<Derived>
_W>{
_W>public:
_W>  int type_tag;
_W>};
_W>


При вызове конструктора базового класса объект Derived еще не существует и обращение к его полям противоречит стандарту. Хотя этот код выполнится без всяких проблем, после завершения конструктора Base, сработает конструктор по умолчанию для Derived и, соответсвенно, конструктор по умолчанию для type_tag, после которого он будет равен 0.

Можно попробовать написать свой конструктор для Derived и не инициализировать type_tag:

// Грязный хак:

// код для Base

class Derived: public Base<Derived>
{
public:
  Derived() {} // отсутсвует инициализация type_tag;

  int type_tag;
};
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re[2]: Чеширский кот и изменение наследника до конструктора
От: MaximE Великобритания  
Дата: 02.09.05 06:09
Оценка:
Здравствуйте, crable, Вы писали:

[]

C>При вызове конструктора базового класса объект Derived еще не существует и обращение к его полям противоречит стандарту. Хотя этот код выполнится без всяких проблем, после завершения конструктора Base, сработает конструктор по умолчанию для Derived и, соответсвенно, конструктор по умолчанию для type_tag, после которого он будет равен 0.


Сгенеренный компилятором ктор по умолчанию не обнуляет члены встроенных типов.
Re[3]: Чеширский кот и изменение наследника до конструктора
От: crable США  
Дата: 02.09.05 09:42
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Здравствуйте, crable, Вы писали:


ME>[]


C>>При вызове конструктора базового класса объект Derived еще не существует и обращение к его полям противоречит стандарту. Хотя этот код выполнится без всяких проблем, после завершения конструктора Base, сработает конструктор по умолчанию для Derived и, соответсвенно, конструктор по умолчанию для type_tag, после которого он будет равен 0.


ME>Сгенеренный компилятором ктор по умолчанию не обнуляет члены встроенных типов.


ошибочка вышла...
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re[2]: Чеширский кот и изменение наследника до конструктора
От: _Winnie Россия C++.freerun
Дата: 02.09.05 13:49
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>_Winnie wrote:


>> Можно так, менять поля наследника до вызова контруктора? Нужно в наследнике создать битовый массив признаков из тех, от кого он отнаследован.


ME>но зачем?


Что бы в runtime проверить из каких компонентов состоит объект неизвестного типа. Объект собирается из них, как из конструктора, но имеет базовый фиксированный класс, из которого полиморфно можно проверить, из чего состоит наследник. На самом деле type_tag находится в это базовом классе.

Но интересно, не запрещает ли стандарт делать static_cast к наследнику, если он еще не сконструирован. Чисто академический интерес
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: Чеширский кот и изменение наследника до конструктора
От: Gleb Alexeev  
Дата: 02.09.05 15:15
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Что бы в runtime проверить из каких компонентов состоит объект неизвестного типа. Объект собирается из них, как из конструктора, но имеет базовый фиксированный класс, из которого полиморфно можно проверить, из чего состоит наследник. На самом деле type_tag находится в это базовом классе.

А rtti не лучше подойдет?

_W>Но интересно, не запрещает ли стандарт делать static_cast к наследнику, если он еще не сконструирован. Чисто академический интерес

Из чисто академического интереса порылся в стандарте ( хорошее упражнение )

5.2.9/8
An rvalue of type “pointer to cv1 B”, where B is a class type, can be converted to an rvalue of type “pointer
to cv2 D”, where D is a class derived (clause 10) from B.... If the rvalue of type “pointer to cv1 B” points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the
cast is undefined.

3.8/1
The lifetime of an object is a runtime property of the object. The lifetime of an object of type T begins
when:
— storage with the proper alignment and size for type T is obtained, and
— if T is a class type with a non-trivial constructor (12.1), the constructor call has completed.

3.8/5
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated ... If the object will be or was of a non-POD class type, the program has
undefined behavior if:
— the pointer is used to access a non-static data member or call a non-static member function of the object,

Мне кажется, что на основании приведенных цитат можно судить, что формально имеем UB.
До того, как закончится конструирование объекта производного класса, нельзя утверждать, что B is actually a sub-object of an object of type D, т.к. объекта типа D еще не существует, так что само преобразование уже является UB. Во-вторых, даже если мы волшебным образом получили валидный указатель, срабатывает 3.8/5.

Пусть меня поправят, если я не прав.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.