Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТП лекции Раздел 4.doc
Скачиваний:
16
Добавлен:
28.09.2019
Размер:
2.56 Mб
Скачать

4.7.1. Разделы в описании класса.

Приведем обобщенную схему описания класса:

class Class_Name {

private:

// Здесь расположены данные и методы, которые недоступны

// извне обычным, прямым способом. Они доступны только в

// методах класса Class_Name, а с их помощью и извне

protected:

// Здесь расположены данные и методы, недоступные прямо.

// Они доступны в методах класса и в методах производных

// классов. Последние будут рассмотрены ниже

public:

// Здесь расположены данные и методы, доступные обычным,

// прямым способом из внешних процедур

};

Тела методов могут быть приведены как внутри каждого из разделов класса, так и вне всего блока описаний, в том числе и в другом файле.

ЗАМЕЧАНИЕ ————————————————————————————————

При отсутствии описателей private, protected и public члены класса по умолчанию имеют тип private. Для структур и union-структур все члены по умолчанию, наоборот, имеют тип public.________________________________________________________________________

Язык C++ временно допускает неполную декларацию класса (incomplete decla­ration). Например:

class А; //Неполная декларация класса А

class В { А *ра; }; // Указатель на класс А — член класса В

class А { В *pb;}; // Класс А декларирован полностью

// Возможные объявления переменных класса А

A obj; // Объект класса А

А *р; // Указатель на объекты класса А

A &ref = obj; // Ссылка на класс А

А аrrау[7]; // Массив объектов класса А

A func(); // Функция, возвращающая объект класса А

Декларировать можно объекты, указатели и ссылки на класс, массивы o6ъектов класса, функции, возвращающие объект класса. Напомним: чтобы послать объекту сообщение, имея только его адрес (р), используется операция выбоpа p->method(). Таким образом, эквивалентны три способа инициации метода класса:

class А { public: void method () { printf ("\nOk"):; } };

void main()

{

A *p, obj; // Указатель и объект класса А p=&obj; // р указывает на obj //----- Три способа вызова функции ---------//

obj.method(); // Сообщение объекту (&obj)->method(); //То же, но с помощью адреса p->method(); // То же, но с помощью указателя }

Заметим, что во втором способе: (&obj)->method() скобки обязательны, так как приоритет операции выбора с помощью указателя выше, чем операции взятия адреса.

Как правило, перед использованием объект должен быть инициализирован. В С этот процесс выполнялся либо автоматически (для глобальных и статических элементов), либо путем определения специальной функции, которая вызывается сразу после создания объекта, до его использования. Аналогичный подход можно использовать и в С++. Однако в нем предусмотрен способ лучше.

4.7.2. Friend-конструкции.

Напомним, что private-данные и методы какого-либо класса прямо доступны только внутри методов класса. Эта ограниченная доступность, с одной стороны, предлагает выгоды, которые предоставляют инкапсуляция и скрытие данных, с другой стороны, накладывает значительную ответственность, так как необходимо обеспечить каждый класс достаточным количеством методов для манипуляции данными во всех реально встречаемых ситуациях. C++ имеет способ обойти это жесткое ограничение и позволить избранным внешним классам, отдельным ме­тодам класса или обычным внешним функциям прямой доступ ко всем данным класса, в том числе и к private. Самое простое — это объявить обычную функ­цию (не являющуюся членом какого-либо класса) friend-функцией класса. Те­перь она имеет доступ ко всем данным и методам класса и может модифициро­вать private-данные класса. Например:

class A {

private:

int i; // private-данное

friend void set (A*, int); // friend-функция

public:

void set (int j) { i=j; } // public-метод

void p() { printf("\n i=%d”,i);}

};

void set (A* p, int i) // Тело friend-функции

{

p->i=i;

}

void main()

{

A obj; // Объект obj класса А

set (&obj, 10); //Доступ с помощью friend-функции

obj.p(); // Вывод поля

obj.set (11); // То же, но с помощью public-метода

obj.p();

}

В примере объявлена внешняя функция set. Она не принадлежит никакому классу. Но она, будучи объявленной friend-функцией класса А, имеет прямой до­ступ к private-переменной класса А, так же, как и метод set собственного класса. Указатель (или ссылку) на объект класса А следует передать в качестве парамет­ра, так как friend-функция является посторонней функцией и не знает объекта obj класса А (в отличие от метода void A::set(int); класса, которому неявно передается указатель this). При вызове внешней функции мы передаем ей &obj — адрес объекта. Этот адрес присваивается локальному указателю р, после чего вы­ражение p->i позволяет обратиться к private-переменной объекта, на который ссылается указатель р. Поле объекта obj прямо доступно внутри friend-функции set. Отметим, что эти же действия можно было осуществить, используя передачу ссылкой. При этом вызов функции должен быть set (obj,10):, ее прототип — friend void set(A&, int);, сама функция — void set (A& a, int i) { a.i=i; }.

Friend-функция может принадлежать какому-либо другому классу. Тогда ее мож­но назвать friend-методом. Чтобы сократить время доступа метода класса В к методу класса А, целесообразно объявить в классе А конкретный метод класса В как friend-метод класса А. Кроме того, в классе А можно объявить весь класс В как friend-клacc класса А. Теперь все методы класса В являются friend-методами класса А, то есть внутренние данные класса А теперь прямо доступны в методах класса В. Объявление friend-конструкций может быть размещено в любой секции (private, protected, public) описания класса. Это не влияет на смысл объявления. Следующая схема иллюстрирует рассмотренные возможности:

class A{

friend int strange(char* ch); // Friend-функция

friend class B; // Friend-класс

friend char* C::methc(); // Friend-метод класса С

};

Свойство friend не транзитивно, то есть если класс В объявлен friend-клас­сом в классе А, а класс С — в классе В, то это не означает, что класс С является friend-классом для класса А («друг моего друга — не мой друг»). При создании производных классов (что будет рассмотрено ниже) следует помнить, что свой­ство friend не наследуется.