Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лекции по ППВиС (17 шт, ppt) Романов ВИ 2011 1ый семестр / Л4_Классы и сокрытие данных_Дружественные функции

.ppt
Скачиваний:
48
Добавлен:
15.06.2014
Размер:
596.48 Кб
Скачать

21

Атрибут доступа

Каждая функция и элемент данных, описанные внутри класса, имеют атрибут доступа:

public (открытый) – доступ к элементам класса может быть осуществлен

как из самого класса, так и извне класса

private (закрытый) – доступ к элементам класса может быть

осуществлен только из функций самого класса.

protected (защищенный) – имеет смысл при наследовании классов и будет рассмотрен позже

По умолчанию все элементы класса имеют атрибут private . Атрибут задается соответствующим ключевым словом и символом «:». Действие атрибута сохраняется до следующего атрибута или до закрывающей фигурной скобки в объявлении класса.

Для структур по умолчанию все элементы класса имеют атрибут public

.

22

Инкапсуляция – идея

class My_cl { public:

void Set(int n);

. . .

protected :

. . .

private:

. . .

};

//public – виден и доступен всем

//protected – виден и доступен только из базового класса и из

// производных классов

// private – виден и доступен только из базового класса

Где либо в программе: My_cl clMy; clMy.Set(a);

V = V1; V = V2; V = V3;
. . .

23

Инкапсуляция - пример

class My_str { public:

void Get(int n); int Var1;

. . .

protected : int Var2;

. . .

private: int Var3;

. . .

};

Где либо в программе: My_str::Get(a);

. . .

void My_str::Get(int a)

{

int V;

};

void main()

{

My_str Obj;

” cannot access protected

Obj.V1 = 1;

member”

Obj.V2 = 1; // Ошибка

Obj.V3 = 1; // Ошибка

}

cannot access private member

24

Дружественные функции – общие положения

При написании программ часто встречается ситуация, при которой необходимо иметь доступ к закрытым компонентам классов. При использовании обычных внешних функций это невозможно – возникают

ошибки компиляции. Для решения данной задачи в С++ применяются так называемые дружественные функции. Для этого используется спецификатор friend. Отмеченная им функция:

не является методом-функцией этого класса;

имеет доступ ко всем компонентам этого класса (даже private).

Прототипы таких функций задаются в теле описания класса. Само тело такой функции может быть описано где угодно – и в классе, и за его пределами.

Лучше производить определение дружественной функции за пределами класса, подчеркивая тем самым тот факт, что функция не является компонентом класса.

25

Дружественная функция (пример)

#include <iostream.h>

using namespace std; class C {

int n; public:

C(int n) {this->n = n; }; // конструктор void print() { cout << "n="<< endl; } friend void inc(C&);

};

void inc (C& obj) { obj.n++; }

void main ()

{ C obj(4); obj.print(); inc(obj); obj.print(); }

26

Дружественная функция – объявление и вызов

Для того, чтобы дружественная функция осуществляла доступ к компонентам класса необходимо в качестве аргумента передавать либо указатель либо ссылку на объект.

Объявлять прототип дружественной функции можно в любом месте описания класса.

Атрибуты доступа для дружественных функций не играют роли.

Так как дружественная функция не является компонентом класса ее нельзя вызвать с использованием имени объекта или указателя на него. Вызов осуществляется обычным способом.

В С++ одна функция не может быть компонентой двух различных классов. Иногда возникает необходимость организации доступа к локальным данным нескольких классов из одной функции. Это еще одна (если не главная!) причина для использования дружественных функций.

27

Дружественная функция (пример 2)

#include <iostream.h>

class B; // ссылка вперед – некоторый // аналог прототипа функции

class C { int k; public:

C(int n) { k = n; }; // конструктор friend char* equal (const C&, const B&);

};

class B { int k; public:

B(int n) { k = n*n; }; // конструктор friend char * equal (const C&, const B&);

};

char* equal (const C &o1, const B &o2)

{

if (o1.k==o2.k) return ("C.k=B.k"); return ("C.k<>B.k");

}

void main ()

{

C obj1(4); B obj2(0);

cout << equal(obj1, obj2) << endl;

}

28

Спецификатор friend классов

Дружественные функции могут быть перегружены.

Любой метод одного класса может быть дружественным по отношению к другому классу. В этом случае для доступа к компонентам классов в качестве аргументов необходимо лишь передать ссылки или указатели на объекты, для которой функция является дружественной.

Предположим, что для предыдущего примера функция equal является методом класса С и дружественной по отношению к классу B.

Тогда описания этой функции будут выглядеть так:

В классе С:

char* equal (const B&);

В классе B:

friend char* C::equal (const B&);

29

Спецификатор friend классов

#include <iostream.h> class A {

int i; public:

friend class B;

A( ) : i(1) { }; // конструктор ~A( ) { };

void f1_A(const B&); };

class B { int j; public:

friend class A;

B( ) : j(2) { }; // конструктор ~B( ) { };

void f1_B(const A& a)

{ cout << a.i + j << endl; }

};

Дружественными могут

быть не только функции, но и классы.

void A::f1_A(const B& b)

{ cout << i <<" "<<b.j << endl; }

void main ( )

{

A aa; B bb;

aa.f1_A(bb); bb.f1_B(aa);

}

Результат выполнения программы:

1 2

3

30

Спецификатор friend классов - свойства

Основные свойства и правила использования спецификации friend.

friend-функции не являются компонентами класса, но имеет доступ ко всем его компонентам;

friend-функции не имеют доступа к указателю this;

friend-функции не наследуются в производных классах;

отношение friend не является ни симметричным, ни транзитивным:

A друг B не значит, что B друг A!

Если A друг B, а B друг C, то это не значит, что A друг C!

друзьями класса можно определить перегруженные функции. Каждая перегруженная функция, используемая как friend для некоторого класса, должна быть явно объявлена в классе со спецификатором friend.