Параметры по умолчанию
связываются на этапе компиляции, а выбор виртуальной функции происходит на
этапе выполнения, потому будет выбран параметр по умолчанию равный типу
указателя (ссылки) через который вызывается виртуальная функция (т.е. тип
базового класса, а не производного).
Причина: Если бы значения аргументов по умолчанию связывались динамически, то
компилятору пришлось бы найти способ во время исполнения определять, какое
значение по умолчанию должно быть у параметра виртуальной функции, что
медленнее и технически сложнее нынешнего механизма. Решение было принято в
пользу скорости и простоты реализации, в результате чего вы можете пользоваться
преимуществами эффективного выполнения кода программы.
Пример:
class Shape {
public:
enum ShapeColor { Red, Green, Blue };
// все фигуры должны предоставлять функцию для рисования
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle: public Shape {
public:
// заметьте, другое значение параметра по умолчанию – плохо!
virtual void draw(ShapeColor color = Green) const;
...
};
class Circle: public Shape {
public:
virtual void draw(ShapeColor color) const;
...
};
Shape *ps; // статический
тип – Shape*
Shape *pc = new Circle; // статический тип – Shape*
Shape *pr = new Rectangle; // статический тип – Shape*
pr->draw();
// вызывается Rectangle::draw(Shape::Red)!
Поскольку статический
тип pr – Shape*, то значения аргумента по умолчанию берутся из класса Shape, а
не Rectangle.
Решение: невиртуальная
функция базового класса + NVI.
Источник: Скотт
Мэйерс Эффективное использование C++. 55
верных способов улучшить структуру и код ваших программ.
По мотивам правила 37.
Комментариев нет:
Отправить комментарий