ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4292
Скачиваний: 28
Глава 14. Классы
181
if (box.isEmpty())
box.put(10);
if (!box.isEmpty())
n = box.get();
cout << n << endl; // печатает 10
return 0;
}
14.4. Указатель
this
По умолчанию каждая не статическая функция-член класса имеет
доступ к указателю с именем
this
, который указывает на объект,
для которого эта функция вызвана. Здесь
this
является ключевым
словом языка программирования С++. Можно сказать, что указа-
тель
this
является неявным параметром каждой функции-члена
класса. Указатель
this
имеет следующий тип:
имя_класса* const
В принципе к любому члену класса, принадлежащему текущему
объекту, можно обратиться через указатель
this
. Например, в
функции-члене класса
IntBox
можно написать так:
this -> empty = false;
Но, т. к. функции-члены класса имеют доступ ко всем членам
класса по умолчанию, то указатель
this
используется в основном
для возврата указателя или ссылки на объект, к которому приме-
няется функция-член класса.
14.5. Спецификаторы доступа
к членам класса
Для ограничения доступа к членам класса вне его области види-
мости используются спецификаторы доступа:
public
,
protected
и
private
, которые также называются
метками
и могут использо-
ваться внутри класса произвольное число раз и в любом порядке.
Часть II. Язык программирования С++
182
Все члены класса, объявленные после метки
public
и располо-
женные до следующей метки, доступны как в классе, так извне
класса.
Все члены класса, объявленные после метки
protected
и распо-
ложенные до следующей метки, доступны только внутри класса и
внутри потомков класса.
Все члены класса, объявленные после метки
private
и располо-
женные до следующей метки, доступны только внутри класса.
По умолчанию все члены класса, объявленные после ключевого
слова
class
до первой метки, имеют спецификацию доступа
private
, а объявленные после ключевых слов
struct
или
union
до
первой метки — спецификацию доступа
public
.
Чтобы запретить пользователям доступ к атрибутам класса
IntBox
, этот класс должен быть определен следующим образом:
class IntBox
{
bool empty; // состояние контейнера
int room; // место для хранения целого числа
public:
IntBox(); // конструктор
void put(int n); // положить целое число в контейнер
int get(); // взять целое число из контейнера
bool isEmpty(); // проверить, свободно ли место
};
Как видим, в этом случае клиенты класса имеют доступ к атрибу-
там класса только через методы этого класса или, как еще гово-
рят, через интерфейс класса. Такой подход к проектированию
структуры класса называется
инкапсуляцией
. Но в этом случае
возникает проблема инициализации атрибута
empty
при опреде-
лении объекта класса. Для этого используются специальные
функции-члены класса, которые называются
конструкторами
.
В нашем случае это функция
IntBox
, которая имеет следующее
определение:
IntBox::IntBox() { empty = true; }
Более подробно конструкторы классов будут рассмотрены в
гл. 15
.
Глава 14. Классы
183
14.6. Друзья класса
При работе с классами может возникнуть следующая проблема.
Допустим, что класс с закрытыми атрибутами определяет тип
параметра функции. Возможна такая ситуация, что эта функция
не может быть реализована, т. к. она не имеет доступа к атрибу-
там экземпляра класса. Чтобы разрешить эту проблему, функция
должна быть объявлена как друг класса.
Второй причиной при определении друзей класса является жела-
ние реализовать более быстрые функции, которые не являются
членами класса, но работают с атрибутами этого класса. Очевид-
но, что прямой доступ к атрибутам класса будет работать быст-
рее, чем доступ к этим же атрибутам через функции-члены класса.
Отношение дружбы нарушает принцип инкапсуляции в объектно-
ориентированном программировании. Поэтому друзей класса нуж-
но выбирать осторожно.
Доступ к закрытым членам класса из другой функции допускает-
ся только в том случае, если она объявлена как друг класса. Объ-
явление друга класса начинается с ключевого слова
friend
и мо-
жет встречаться только внутри определения класса. Так как
друзья класса не являются членами класса, то не имеет значения
после какой из меток они объявлены. Друзьями класса могут
быть объявлены как функции из пространства имен, так и функ-
ции-члены другого класса.
Определяются функции-друзья класса как обычные функции
внутри или вне класса. Если функция определяется внутри клас-
са, то это определение одновременно является и объявлением
функции. В этом случае имя функции принадлежит тому же про-
странству имен, что и имя класса. Если функция друг класса оп-
ределяется вне класса, то при этом ключевое слово
friend
не ис-
пользуется.
Например, объявим для класса
IntBox
две дружественные функ-
ции:
in
и
out
, которые соответственно предназначены для ввода
целого числа в контейнер с консоли и для вывода целого числа из
Часть II. Язык программирования С++
184
контейнера на консоль. Тогда определение класса
IntBox
будет
выглядеть следующим образом:
class IntBox
{
bool empty; // состояние контейнера
int room; // место для хранения целого числа
public:
IntBox(); // конструктор
void put(int n); // положить целое число в контейнер
int get(); // взять целое число из контейнера
bool isEmpty(); // проверить, свободно ли место
friend void in(IntBox& box); // ввод числа с консоли
friend void out(IntBox& box); // вывод числа на консоль
};
Реализацию этих функций можно поместить как в исходный файл
IntBox.cpp, так и в новый исходный файл. Выберем второй вари-
ант и создадим исходный файл InOutBox.cpp. В листинге 14.4
приведен текст этого файла.
Листинг 14.4. Реализация функций-друзей класса
#include "IntBox.h"
#include <iostream>
using namespace std;
void in(IntBox& box)
{
cin >> box.room;
box.empty = false;
}
void out(IntBox& box)
{
cout << box.room;
box.empty = true;
}
В листинге 14.5 показано, как использовать эти функции для вво-
да целого числа с консоли в контейнер и вывода этого же целого
числа на консоль из контейнера.
Глава 14. Классы
185
Листинг 14.5. Использование функций-друзей класса
#include "IntBox.h"
#include <iostream>
using namespace std;
int main()
{
IntBox box;
cout << "Input integer: ";
in(box);
out(box);
cout << endl;
return 0;
}
Друзьями класса могут быть также объявлены другие классы.
В этом случае доступ к закрытым членам класса допускается для
всех функций друга этого класса. Например, объявим для класса
IntBox
дружественный класс
PrintBox
, который содержит функ-
цию для вывода на консоль целого числа, хранящегося в контей-
нере, не удаляя его оттуда. Тогда определение класса
IntBox
бу-
дет выглядеть следующим образом:
class IntBox
{
bool empty; // состояние контейнера
int room; // место для хранения целого числа
public:
IntBox(); // конструктор
void put(int n); // положить целое число в контейнер
int get(); // взять целое число из контейнера
bool isEmpty(); // проверить, свободно ли место
friend void in(IntBox& box); // ввод числа с консоли
friend void out(IntBox& box); // вывод числа на консоль
friend struct PrintBox; // печать содержимого контейнера
};