Помните, что класс сам является областью видимости (см. раздел 2.6.1). Определения функций-членов класса находятся в области видимости самого класса. Следовательно, использованное функцией isbn() имя bookNo относится к переменной-члену, определенной в классе Sales_data.
Следует заметить, что функция isbn() может использовать имя bookNo, несмотря на то, что оно определено isbn(). Как будет описано в разделе 7.4.1, компилятор обрабатывает классы в два этапа — сначала объявления членов класса, затем тела функций-членов, если таковые вообще имеются. Таким образом, тела функций-членов могут использовать другие члены своих классов, независимо от того, где именно в классе они определены.
Подобно любой другой функции, при определении функции-члена вне тела класса ее определение должно соответствовать объявлению. Таким образом, тип возвращаемого значения, список параметров и имя должны совпадать с объявлением в теле класса. Если член класса был объявлен как константная функция, то в определении после списка параметров также должно присутствовать ключевое слово const. Имя функции-члена, определенное вне класса, должно включить имя класса, которому она принадлежит:
double Sales_data::avg_price() const {
if (units_sold)
return revenue/units_sold;
else
return 0;
}
Имя функции, Sales data::avg_price(), использует оператор области видимости (см. раздел 1.2), чтобы указать, что определяемая функция по имени avg_price объявлена в пределах класса Sales_data. Как только компилятор увидит имя функции, остальная часть кода интерпретируется как относящаяся к области видимости класса. Таким образом, когда функция avg_price() обращается к переменным revenue и units_sold, она неявно имеет в виду члены класса Sales_data.
this на объектФункция combine() должна действовать как составной оператор присвоения +=. Объект, для которого вызвана эта функция, представляет собой левый операнд присвоения. Правый операнд передается как аргумент явно:
Sales_data& Sales_data::combine(const Sales_data &rhs) {
units_sold += rhs.units_sold; //
revenue += rhs.revenue; //
return *this; //
}
Когда наша программа обработки транзакций осуществляет вызов
total.combine(trans); //
адрес объекта total находится в неявном параметре this, а объект trans связан с параметром rhs. Таким образом, при вызове функции combine() выполняется следующий оператор:
units_sold += rhs.units_sold; //
В результате произойдет сложение переменных total.units_sold и trans.units_sold, а сумма должна сохраниться снова в переменной total.units_sold.
Самым интересным в этой функции является тип возвращаемого значения и оператор return. Обычно при определении функции, работающей как стандартный оператор, она должна подражать поведению этого оператора. Стандартные операторы присвоения возвращают свой левый операнд как l-значение (см. раздел 144). Чтобы возвратить l-значение, наша функция combine() должна возвратить ссылку (см. раздел 6.3.2). Поскольку левый операнд — объект класса Sales_data, тип возвращаемого значения — Sales_data&.
Как уже упоминалось, для доступа к члену объекта, функция-член которого выполняется, необязательно использовать неявный указатель this. Однако для доступа к объекту в целом указатель this действительно нужен:
return *this; //
Здесь оператор return обращается к значению указателя this, чтобы получить объект, функция которого выполняется. Таким образом, для этого вызова возвращается ссылка на объект total.
Упражнение 7.2. Добавьте функции-члены combine() и isbn() в класс Sales_data, который был написан для упражнений из раздела 2.6.2.
Упражнение 7.3. Пересмотрите свою программу обработки транзакций из раздела 7.1.1 так, чтобы использовать эти функции-члены.
Упражнение 7.4. Напишите класс по имени Person, представляющий имя и адрес человека. Используйте для содержания каждого из этих членов тип string. В последующих упражнениях в этот класс будут добавлены новые средства.