Как правильно воздержаться от CS2512

Пожалуйста, помогите мне со следующей проблемой:

У меня есть следующие классы:

class ChemicalElement
{
private:
    std::string _name;
    void Init(const std::string& name);
public:
    ChemicalElement(const std::string& name);
    ChemicalElement(const ChemicalElement& ce);
};

class CombinationRule
{
private:
    ChemicalElement _ce1;
    ChemicalElement _ce2;
    void Init(const ChemicalElement& ce1, const ChemicalElement& ce2);
public:
    CombinationRule(const ChemicalElement& ce1, const ChemicalElement& ce2);
    CombinationRule(const CombinationRule& rule);
};

Реализация очевидна. Я намеревался инициализировать CombinationRule, используя метод Init, чтобы минимизировать дублирование кода. Увы, если я не использую "список инициализации элементов" в каждом конструкторе, компилятор выдает сообщение "ошибка C2512:" ChemicalElement ": не доступен соответствующий конструктор по умолчанию". Есть ли элегантный способ решить эту ошибку вместо использования конструктора по умолчанию или списка инициализации члена? Кстати: если есть какие-то другие проблемы в определении классов, пожалуйста, добавьте их тоже. Так как я пересматриваю C++, я хочу знать о них.

4 ответа

Решение

Вы должны реализовать конструкторы CombinationRule следующим образом, поэтому они будут использовать соответствующие конструкторы ChemicalElement:

CombinationRule::CombinationRule(const ChemicalElement& ce1, 
  const ChemicalElement& ce2) : _ce1(ce1), _ce2(ce2) 
{ 
  ... 
}

CombinationRule::CombinationRule(const CombinationRule& rule) : 
  _ce1( rule._ce1 ), _ce2( rule._ce2 )
{
  ...
}

Я думаю, что вы должны поместить конструктор по умолчанию в любой класс, где вы определяете любые другие конструкторы, если вы хотите использовать объекты этого класса в любом виде массива или контейнера. Реализация конструктора по умолчанию может быть просто пустым / no-op методом.

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

Я думаю, что вы хотите этого

ChemicalElement * ce1;

Я говорю это, потому что я думаю, что он пытается запустить конструктор по умолчанию на вашем CombinationRule и, в свою очередь, должен получить ChemicalElement для ce1 и ce2 ... но я могу ошибаться.

Уверен, что путь Криля - это способ указать конструктор переменной для конкретного конструктора, НО я сказал это и только что сделал это, так что компилятор не должен создавать ce1:)

В этом конкретном примере я бы продолжил дублирование (это просто написание двух инициализаторов, не за что одержимо).

Но предположим, что реальная история более сложна: используйте возможности OO, чтобы избежать дублирования кода.

class CombinationRule : public ElementPair ...

или же

class Combination { ElementPair twoElements; ...}

Где ElementPair содержит два ChemicalElements и один конструктор (с общим кодом), а конструкторы правил Combination инициализируются с использованием конструктора ElementPair.

Существуют и другие подходы: инициализация членов с некоторым экземпляром InvalidChemicalElement или использование указателей (auto_ptr) с NULL для InvalidChemicalElement.

Другие вопросы по тегам