От Мышление в C ++ Vol. 1 (Р-33):
Композиция имеет большую гибкость. Член
объекты вашего нового класса обычно являются частными, что делает их
недоступен клиентским программистам, использующим класс. это
позволяет изменить эти элементы, не нарушая существующие
код клиента
Вы также можете изменить объекты-члены во время выполнения, чтобы
динамически изменять поведение вашей программы. Наследование,
который описан ниже, не обладает такой гибкостью, поскольку
компилятор должен наложить ограничения во время компиляции на созданные классы
с наследством.
Как мы можем изменить объекты-члены во время выполнения в составе?
Разве объекты не включены при написании объявления класса?
class car
{
private:
engine obj;
}
Итак, вот класс car
содержит объект класса engine
, Как мы можем изменить это во время выполнения?
Или я что-то упустил?
Попробуйте вместо этого использовать указатель на ваш объект-член:
class car {
engine *obj;
}
Теперь вы можете выбрать во время выполнения, использовать ли экземпляр rotary_engine
или же v8_engine
или же flux_capacitor_engine
,
Конечно, вы можете использовать что-то вроде unique_ptr
или shared_ptr
управлять владением и временем жизни объекта-члена.
Это действительно немного расплывчатое утверждение.
Композиция определяет has-a
отношения, т.е. car
имеет engine
. Вы можете заменить двигатель вашего автомобиля, и автомобиль все равно останется автомобилем.
Наследование определяет is-a
отношения, т. е. если бы вы определили автомобиль как наследство от двигателя, это означало бы car
является engine
. Замена двигателя будет означать изменение самого типа автомобиля — если вы измените базовый класс, он автоматически изменит производный класс. Это ограничение не существует при использовании композиции.
Таким образом, в вашем примере композиция является правильным способом.
Для чистого состава также возможны изменения времени выполнения:
class Car {
private:
CarPart &get_part(int i) const {
switch(i) {
case 0: return e;
case 1: return w1;
case 2: return w2;
case 3: return w3;
case 4: return w4;
}
}
private:
Engine e;
Wheel w1, w2, w3, w4;
};
Тогда, например, установить свойства легко:
void set_property(int id, std::string name, int value) {
CarPart &p = get_part(id);
p.set(name, value);
}
Это настолько динамично, насколько вы можете получить …