Как правильно воздержаться от 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.