virtual void draw(ShapeColor color = Red) const;
...
};
Гм, дублирование кода! Хуже того: дублирование кода с зависимостями: если значение аргумента по умолчанию изменится в Shape, придется изменить его и во всех производных классах. В противном случае дело закончится переопределением наследуемого значения по умолчанию. Что делать?
Когда у вас возникает проблема с тем, чтобы заставить виртуальную функцию вести себя так, как вы хотите, то благоразумнее рассмотреть альтернативные решения, и в правиле 35 таких альтернатив приведено немало. Одна из них –
class Shape {
public:
enum ShapeColor( Red, Green, Blue };
void draw(ShapeColor color = Red) const // теперь – невиртуальная
{
doDraw(color); // вызов виртуальной функции
}
...
private:
virtual void doDraw(ShapeColor color) const = 0; // реальная работа
}; // выполняется
// в этой функции
class Rectangle: public Shape {
public:
...
private:
virtual void doDraw(ShapeColor color) const // обратите внимание
... // на отсутствие у аргумента
}; // значения по умолчанию
Поскольку невиртуальные функции никогда не должны переопределяться в производных классах (см. правило 36), то ясно, что при таком подходе значение по умолчанию для параметра color функции draw всегда будет Red.
• Никогда не переопределяйте наследуемые значения аргументов по умолчанию, потому что аргументы по умолчанию связываются статически, тогда как виртуальные функции – а только их и можно переопределять, – динамически.
Правило 38: Моделируйте отношение «содержит» или «реализуется посредством» с помощью композиции
class Address {...}; // адрес проживания
class PhoneNumber {...};
class Person {
public:
...
private:
std::string name; // вложенный объект
Address address; // то же
PhoneNumber voiceNumber; // то же
PhoneNumber faxNumber; // то же
};
В данном случае объекты класса Person включают в себя объекты классов string, Address и PhoneNumber. Термин
В правиле 32 объясняется, что открытое наследование означает «класс является разновидностью другого класса». У композиции тоже есть семантика, даже две: «содержит» или «реализуется посредством». Дело в том, что в своих программах вы имеете дело с двумя различными областями. Некоторые программные объекты описывают сущности из моделируемого мира: людей, автомобили, видеокадры и т. п. Такие объекты являются частью
Вышеприведенный класс Person демонстрирует отношение типа «содержит». Объект Person имеет имя, адрес, номера телефона и факса. Нельзя сказать, что человек