В моем коде я считаю полезным использовать наследование, подобное миксину, для компоновки объектов с разными блоками. У меня есть:
class Name
{
public:
typedef int32_t value_type;
public:
// ctors and dtors
void set_value(value_type value) { value_ = value; }
const value_type& value() const { return value_; }
private:
value_type value_;
};
class NamedObject
{
public:
void set_name(const Name& name) { name_ = name; }
const Name& name() const { return name_; }
protected:
// ctors and dtors
private:
Name name_;
};
И я использую этот вид базовых классов для предоставления объектам свойств с заранее определенной невиртуальной функциональностью:
class MyObject: public NamedObject, public HasZlevel {
// functionality that is not connected with NamedObject and HasZLevel
};
Поэтому я решаю рассматривать MyObject как «is-a» NamedObject вместо «has-a» "Имя. Z-level и Name - это свойства, которые никогда не изменятся в течение жизни экземпляра MyObject. Я предпочитаю это агрегации из-за упрощенного использования в алгоритмах, которые определены только для NamedObjects, или для объектов, имеющих интерфейс HasZLevel, я могу передать их через NamedObject * или HasZLevel * и быть уверенным, что они не будут удалены или добавлены из-за защищенных dtors и ctors.
Другой вариант - агрегация:
class MyObject
{
public:
MyObject(const Name& name): name_(name) {}
void set_name(const Name& name) { named_->set_name(name) }
// and so on...
private:
Name name_;
};
Чтобы использовать это, мне нужен шаблонный алгоритм, который требует от типа параметра, чтобы он имел функцию-член set_name.
Есть ли в моем случае какие-либо веские причины отказаться от моего подобного миксину спроектировать и использовать агрегацию? Может быть, при долгосрочном обслуживании и модификации?