C++: варианты инициализации класса-члена без неявного конструктора по умолчанию (дополнительные ограничения в тексте вопроса)

boost::posix_time::time_duration имеет три перегрузки конструктора и не имеет неявного конструктора. Мне нужно сделать некоторые вычисления в классе, который имеет несколько членов time_duration, прежде чем я смогу их инициализировать. Все это подразумевает, что без конструктора по умолчанию я не могу позволить себе роскошь подготовки входных данных для членов моего класса в конструкторе составного класса.

Схема может быть описана следующим образом (что ошибочно):

class X {
public:
    x(int i,int j){}
};

class Y {
  x _x; 
public:
    y() {i = 1+1; j=1-1; _x(i,j);}
};

int main()
{
    return 0;
}

Я хотел бы, чтобы некоторые соответствующие способы построения Y (с мотивацией), где

  1. X не имеет конструктора по умолчанию.
  2. X не может быть изменен напрямую (но может быть подклассом).
  3. Сгенерированный код является детерминированным (нет ненужных дорогостоящих конструкций malloc/vtables и т.д.).
  4. Ключевая точка Класс Y имеет n X членов и m возможных вычислений. Где n >1 и m > 1. Так что элегантность важна.
  5. Соображения модульного тестирования важны.

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


person Hassan Syed    schedule 14.12.2010    source источник
comment
Можно ли назначать time_duration? Версия, которую я установил, является как конструируемой по умолчанию, так и назначаемой, но она довольно старая. Если его можно присваивать и вы не хотите вычислять правильное значение в списке инициализаторов, просто инициализируйте его каким-нибудь фиктивным значением, например seconds(0), и присвойте правильное значение в конструкторе. Если вы вычисляете несколько длительностей из нескольких входных данных, то выполнение всего этого в функциях, вызываемых из списка инициализаторов, может привести к дублированию работы, поэтому разумно этого избегать.   -  person Steve Jessop    schedule 14.12.2010


Ответы (1)


Извините, если я неправильно понял ваш вопрос, но это не Boost.Optional решение вашей проблемы? Вероятно, это лучший способ достичь неинициализированного состояния по умолчанию, не прибегая к указателям и динамическому размещению.

Однако, хотя это сработает, это, вероятно, не идеально. Мое решение, вероятно, было бы, если это возможно, перенести вычисления в свободных функциях в анонимное пространство имен:

namespace {
    x computeX()
    {
        int i, j = /* ... */;
        return x(i, j);
    }
}

y::y()
  : _x(computeX())
{
    /* ... */
}
person icecrime    schedule 14.12.2010
comment
Действительно (+1) Это поразило меня сегодня, когда я ехал на работу :D. Я не знаком с деталями, AFAIK необязательно расширит составной класс - по крайней мере, если он использует переменную для состояния, нет? - person Hassan Syed; 14.12.2010
comment
@Hassan: да, в каждом boost::optional есть дополнительное логическое значение - person icecrime; 14.12.2010