friend std::ostream &print(std::ostream&, const Sales_data&);
//
public:
Sales_data() = default;
Sales data(const std::string &s, unsigned n, double p):
bookNo(s), units_sold(n), revenue (p*n) { }
Sales_data(const std::string &s): bookNo(s) { }
Sales_data(std::istream&);
std::string isbn() const { return bookNo; }
Sales_data &combine(const Sales data&);
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//
//
Sales_data add(const Sales_data&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);
std::ostream &print(std::ostream&, const Sales_data&);
Объявления друзей могут располагаться только в определении класса; использоваться они могут в классе повсюду. Друзья не являются членами класса и не подчиняются спецификаторам доступа раздела, в котором они объявлены. Более подробная информация о дружественных отношениях приведена в разделе 7.3.4.
Объявление дружественных отношений устанавливает только право доступа. Это не объявление функции. Если необходимо, чтобы пользователи класса были в состоянии вызвать дружественную функцию, ее следует также объявить.
Чтобы сделать друзей класса видимыми его пользователям, их обычно объявляют вне класса в том же заголовке, что и сам класс. Таким образом, в заголовке Sales_data
следует предоставить отдельные объявления (кроме объявлений дружественными в теле класса) для функций read()
, print()
и add()
.
Некоторые компиляторы позволяют вызвать дружественную функцию, когда для нее нет обычного объявления. Даже если ваш компилятор позволяет такие вызовы, имеет смысл предоставлять отдельные объявления для дружественных функций. Так не придется переделывать весь код, если вы перейдете на компилятор, который выполняет это правило.
Упражнение 7.20. Когда полезны дружественные отношения? Укажите преимущества и недостатки их использования.
Упражнение 7.21. Измените свой класс Sales_data
так, чтобы скрыть его реализацию. Написанные вами программы, которые использовали операции класса Sales_data
, должны продолжить работать. Перекомпилируйте эти программы с новым определением класса, чтобы проверить, остались ли они работоспособными.
Упражнение 7.22. Измените свой класс Person
так, чтобы скрыть его реализацию.
7.3. Дополнительные средства класса
Хотя класс Sales_data
довольно прост, он все же позволил исследовать немало средств поддержки классов. В этом разделе рассматриваются некоторые из дополнительных средств, связанных с классом, которые класс Sales_data
не будет использовать. К этим средствам относятся *this
, а также подробности определения и использования типов класса и дружественных классов.
7.3.1. Снова о членах класса
Для исследования некоторых из дополнительных средств определим пару взаимодействующих классов по имени Screen
и Window_mgr
.
Класс Screen
представляет окно на экране. У каждого объекта класса Screen
есть переменная-член типа string
, хранящая содержимое окна и три переменные-члена типа string::size_type
, представляющие позицию курсора, высоту и ширину окна.
Кроме переменных и функций-членов, класс может определять собственные локальные имена таких типов. Определенные классом имена типов подчиняются тем же правилам доступа, что и любой другой его член, и могут быть открытыми или закрытыми:
class Screen {
public: