Что происходит при вызове этой функции?
Ясно, что вызывается конструктор копирования Student для инициализации параметра plato. Также ясно, что s уничтожается при возврате из validate-Student. Поэтому передача параметра по значению этой функции обходится в один вызов конструктора копирования Student и один вызов деструктора Student.
Но это еще не все. Объект Student содержит внутри себя два объекта string, поэтому каждый раз, когда вы конструируете объект Student, вы должны также конструировать и эти два объекта. Класс Student наследует класу Person, поэтому каждый раз, конструируя объект Student, вы должны сконструировать и объект Person. Но объект Person содержит еще два объекта string, поэтому каждое конструирование Person влечет за собой два вызова конструктора string. Итак, передача объекта Student по значению приводит к одному вызову конструктора копирования Student, одному вызову конструктора копирования Person и четырем вызовам конструкторов копирования string. Когда копия объекта Student разрушается, каждому вызову конструктора соответствует вызов деструктора, поэтому общая стоимость передачи Student по значению составляет шесть конструкторов и шесть деструкторов!
Что ж, это корректное и желательное поведение. В конец концов, выbool validateStudent(const Student& s);
Этот способ гораздо эффективнее: не вызываются никакие конструкторы и деструкторы, поскольку не создаются никакие новые объекты. Квалификатор const в измененном объявлении параметра важен. Исходная версия validateStudent принимала параметр Student по значению, вызвавший ее знает о том, что он защищен от любых изменений, которые функция может внести в переданный ей объект; validateStudent сможет модифицировать только его копию. Теперь же, когда Student передается по ссылке, необходимо объявить его const, поскольку в противном случае вызывающая программа должна побеспокоиться о том, чтобы validateStudent не вносила изменений в переданный ей объект. Передача параметров по ссылке также позволяет избежать проблемы «
class Window {
public
…
std::string name() const; // возвращает имя окна
virtual void display() const; // рисует окно и его содержимое
};
class WindwoWithScrollBars: public Window {
public:
…
virtual void display() const;
};Все объекты класса Window имеют имя, которое вы можете получить посредством функции name, и все окна могут быть отображены, на что указывает наличие функции display. Тот факт, что display – функция виртуальная, говорит о том, что способ отображения простых объектов базового класса Window может отличаться от способа отображения объектов WindowWithScrollBar (см. правила 34 и 36). Теперь предположим, что вы хотите написать функцию, которая будет печатать имя окна и затем отображать его. Вот