Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 400107.doc
Скачиваний:
5
Добавлен:
30.04.2022
Размер:
568.32 Кб
Скачать
      1. Дружественные функции

Дружественная функция класса – это функция, которая сама не является членом класса, но имеет полные права доступа к элементам класса типа private и protected. Дружественные функции объявляются с помощью спецификатора friend. Поскольку такая функция не является членом класса, то она не может быть выбрана с помощью операций . и -> (имя_класса.имя_функции).

Пример:

class X

{

int i;

friend void func1(X*,int);

public:

void func2(int);

};

/* определение функций */

void func1(X* ptr, int a)

{ptr->i=a;} //доступ по указателю к члену private

void X::func2 (int a)

{i=a;} //прямой доступ к i

Фрагмент программы:

X obj; //объект класса Х

func1 (&obj, 6); //вызов дружественной функции для объекта obj

//переменная obj::i получит значение 6

obj.func2(6); //вызов обычной функции, члена класса Х

Как видно из примера:

дружественная функция определяется вне класса, без ссылки на класс;

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

одна и та же функция может быть дружественной для нескольких классов.

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

class X {friend Y; //все функции, описанные в классе Y дружественны для X

int i;

….};

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

class X {… void xf(..); …};

class Y {int i; friend void X::xf(..); …}; //Функция xf(..) – член класса Х стала

// дружественной для класса Y

      1. Конструкторы и деструкторы

Конструктор – функция, имя которой совпадает с именем класса. Конструктор может иметь список формальных параметров как любая другая функция. Конструктор не может возвращать значение; тип значения нельзя задавать, не допускается даже описатель void. Конструктор запускается автоматически при объявлении объектов данного класса. Вывод: при объявлении класса должны быть даны фактические параметры конструктора (если они имеются). Допускается иметь в одном классе несколько конструкторов с разным составом формальных параметров. В последнем случае выбор конструктора осуществляется в зависимости от заданных параметров. Конструкторы не наследуются, допускается вызов необходимых конструкторов базовых классов из порожденного класса.

Пример 1. Простейший конструктор.

class date

{… date (int, int, int); …};

Объявление объектов класса date:

date today (17, 6, 1994); // конкретный день

date christmas (25, 12, 0); // рождество

date birthday; //ошибка, нет значений параметров

Пример 2. Конструктор с присвоением начальных значений в самом классе.

class date

{ int day, month, year;

public:

date (int d=1, int m=1, int y=1); …

};

Теперь дрпустимы: date today (17, 6, 94); //новое значение

date default; //значение по умолчанию

Пример 3. Несколько конструкторов.

class X

{

int k;

float f;

public:

X (int i) {k=i;};

X (float z) {f=z;}; //2 конструктора

…};

main()

X one (10); //выбирается первый конструктор

X two (3.14); //выбирается второй конструктор

В последнем примере создаются два объекта класса Х:

one – инициализируется переменная k (k=10),

two - инициализируется переменная f (f=3.14).

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

Пример 4. Простейший список инициализации.

class Y

{

int a,b;

public:

X (int i, int j):a(i), b(j){}; };

Запсиь Х х(1,2); вызывает присвоения a=1; b=2.

Пример 5. Использование списка инициализации при наличии базовых классов.

class base1

{

int x;

public:

base1 (int i) {x=i;};

};

int y;

public:

base2 (int i): y(i) {};

};

class top :public base1, public base2 //класс top имеет 2 базовых

{

int a,b;

public:

top (int i, int j): base1(i*5), base2(j+i), a(i)

{b=j;};

};

Так как конструкторы базовых классов имеют параметры, то их инициализация предусмотрена в порожденном классе. Объявление top one(1,2); вызывает инициализацию: base1 с параметром 5; base2 с параметром 3; и устанавливает one.a=1; one.b=2.

Деструктор – функция-член класса, которая выполняет действия, противоположные конструктору. Объект какого-то класса возникает при его объявлении. Тогда же запускается и его конструктор, который позволяет инициализировать объект, т.е. присвоить значения его переменным. Объект уничтожается при выходе из блока, в котором действительно его имя. Говорят, что в таком случае автоматически вызывается деструктор этого класса. Деструктор в С++ имеет стандартное имя ~имя-класса. В деструктор следует включать действия, которые необходимо выполнить непосредственно перед уничтожением объекта (например, закрытие файлов). Если таких действий нет, то объект может не иметь деструктора. Деструктор не имеет параметров, для него не указывается тип результата.

Как другие переменные, так и объекта в ходе выполнения программы могут создаваться и уничтожаться динамически. При создании объекта запускается конструктор, при уничтожении – деструктор.

Пример6. Стек для символов.

class c_stack

{

int size;

char* top;

char* stack;

public:

c_stack (int s) //конструктор

{top = stack = new char [size = s];}

~c_stack() //деструктор

{ delete stack; }

void push (char c)

{*top++ =c; }

char pop()

{ return*--top;}

};

void not_much ()

{

c_stack char_stack1(100);

c_stack char_stack2(200);

char_stack1.push(‘a’);

char_stack2.push(char_stack1.pop());

}

Конструктор и деструктор содержат, соответственно, new и delete. Когда завершается блок, в котором был определен объект класса c_stack, автоматически вызывается деструктор. Естественно, допускается и явный вызов деструктора. При вызове not_much дважды вызывается конструктор c_stack: для создания стеков объёмом 100 и 200 символов соответственно. При завершении функции not_much оба стека автоматически стираются.