Как я могу хранить в производном классе информацию, полученную при инициализации базового класса?

У меня возникла ситуация, когда в качестве побочного эффекта при получении данных для инициализации базового класса производный класс вычисляет часть информации, которая впоследствии должна быть доступна через его интерфейс. Следующее дает представление о проблеме, используя логическое значение в качестве требуемой информации:

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.

2 ответа

Решение

В 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;
};
Другие вопросы по тегам