У меня возникла ситуация, когда в качестве побочного эффекта при получении данных для инициализации базового класса производный класс вычисляет часть информации, которая впоследствии должна быть доступна через его интерфейс. Следующее дает представление о проблеме, используя логическое значение в качестве требуемой информации:
class base {
public:
base(some_initialization_data);
// ...
};
class derived : public base {
public:
derived()
: base(calc_init_data())
{
}
bool condition_x_occurred() const
{
// How to get at the information obtained
// during the call to calc_init_data()?
}
private:
static some_initialization_data calc_init_data()
{
// This piece of information will later be needed:
const bool condition_x_occurred = /* ... */;
return some_initialization_data(condition_x_occurred);
}
};
Проблема заключается в том, что важная часть информации вычисляется во время инициализации базового класса, прежде чем инициализируются собственные члены данных производного класса. Поэтому я пока не должен писать в элементы данных производного класса. Хотя я уверен, что смогу избежать неприятностей с логическим значением, еще не созданным официально на любой платформе, с которой я столкнулся за последние 20 лет, я бы хотел избежать вызова неопределенного поведения.
Обратите внимание, что рассматриваемая информация не имеет никакого отношения к базовому классу, поэтому хранить ее в базовом классе не вариант. Также информация не может быть сохранена в статическом элементе данных. У меня есть несколько идей о том, как реорганизовать код, чтобы я мог это сделать, но те, которые я мог придумать, кажутся довольно навязчивыми для такой маленькой проблемы. Поэтому мне интересно, может ли кто-нибудь из вас придумать что-нибудь простое?
Заметка: Так как мы на встроенной платформе, мы застряли с GCC 4.1.2. Так что строго C ++ 03 (включая TR1), но не C ++ 11.
в C ++ 11 вы можете сделать что-то вроде:
class derived : public base {
public:
derived() : derived(calc_init_data()) {}
bool condition_x_occurred() const { return my_condition_x_occurred; }
private:
derived(const std::pair<bool, some_initialization_data>& p) :
base(p.second), my_condition_x_occurred(p.first)
{}
static std::pair<bool, some_initialization_data> calc_init_data()
{
// This piece of information will later be needed:
const bool condition_x_occurred = /* ... */;
return std::make_pair(condition_x_occurred, some_initialization_data(condition_x_occurred));
}
private:
bool my_condition_x_occurred;
};
В C ++ 03 вы можете изменить свой производный класс на что-то вроде:
class derived : public base {
public:
static derived make_derived() { return derived(calc_init_data()); }
bool condition_x_occurred() const { return my_condition_x_occurred; }
private:
derived(const std::pair<bool, some_initialization_data>& p) :
base(p.second), my_condition_x_occurred(p.first)
{}
static std::pair<bool, some_initialization_data> calc_init_data()
{
// This piece of information will later be needed:
const bool condition_x_occurred = /* ... */;
return std::make_pair(condition_x_occurred, some_initialization_data(condition_x_occurred));
}
private:
bool my_condition_x_occurred;
};
Если доступно на вашем компиляторе, вы можете использовать делегирующий конструктор:
struct derived_init
{
bool data;
some_initialization_data calc()
{
data = true;
return some_initialization_data();
}
};class derived : public base {
public:
derived()
: derived(derived_init{})
{ }
bool condition_x_occurred() const
{
return init_data.data;
}
private:
derived(derived_init init)
: base(init.calc()), init_data(init)
{ }
derived_init init_data;
};
С C ++ 03 вы можете использовать аргумент по умолчанию:
class derived : public base {
public:
derived(derived_init init = derived_init{})
: base(init.calc()), init_data(init)
{
}
private:
derived_init init_data;
};