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

Sb97282

.pdf
Скачиваний:
1
Добавлен:
13.02.2021
Размер:
998.17 Кб
Скачать

2. Имя конструктора_ имя объекта (список аргумента): sumz(5,7);

2.1. Перегруженный конструктор

Пример: class data

{

int day, month, year; public:

data (int a, int b, int c); data (void);

data (int);

………..

};

data :: data (int a, int b, int c)

{

day = a; month = b; year = c;

}

data :: data (void)

{day = 1; month = 1; year = 1989; } data :: data (int x)

{day = x; month = 3; year = 2007; } data d1 (2, 8, 2006);

data my_birthday; data today (2);

Компилятор в зависимости от количества и типов параметров сам выбирает нужный конструктор.

2.2. Деструкторы

Деструкторы – это специальные функции-члены, которые уничтожают объекты класса и освобождают занимаемую этими объектами память; также осуществляют восстановление экрана, закрытие файла и т. д.

Деструктор имеет такое же имя, как и класс, но перед ним ставится знак тильда ~.

11

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

data :: ~data() {…}

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

Пример: составить программу, осуществляющую вычисление по форму-

ле: S = a*b + c*k + a*c. #include <iostream.h> class Pro

{

int x, y, z; public:

Pro (int, int);

int put x (); int put y (); int put z (); voidproizv (void);

~Pro ();

};

Pro :: Pro (int x1, int y1) { x = x1; y = y1; }

int Pro :: put x () {return x ;} int Pro :: put y () {return y ;} int Pro :: put z () {return z ;} void Pro :: proizv () {z = x*y ;} Pro :: ~Pro () {}

void main ()

{

int S, a, b, c, k;

cout<< “\n Введите a, b, c и k \n”; cin>> a >> b >> c >> k;

Pro D = Pro (a, b); Pro E (c, k);

Pro F (a, c); D.proizv ();

S = D.put z () + E.put z () +F.put z ();

12

cout<< “сумма = “<<S; F. Pro :: ~ Pro ();

E. Pro :: ~ Pro ();

D. Pro :: ~ Pro ();

}

3.ДРУЖЕСТВЕННЫЕ ФУНКЦИИ

ИДРУЖЕСТВЕННЫЕ КЛАССЫ

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

Функция – не член класса, получившая право доступа к закрытой части класса, называется дружественной функцией. Функция становится дружественной после описания при помощи ключевого слова friend.

Фрагмент: class CL {

public:

friend void frd (void);

};

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

Пример: два класса vector и matrix, каждый скрывает свое представление и предоставляет полный набор действий для манипуляций с объектами его типа:

vector – целочисленный массив из 4 элементов; индексы изменяются

0–3;

matrix – массив из 4 векторов; индексы изменяются 0–3.

Доступ к элементам матрицы и вектора осуществляется через похожие функции elem:

int elem (int i);

int elem (int i, int y).

Задача: определить функцию, обеспечивающую умножение матрицы на вектор.

13

Способ 1. При помощи глобальной функции multiply(): vector multiply(matrix &m, vector &v)

{

vector r;

for (int i=0; i<3; i++){ r.elem (i) = 0;

for (int j = 0; j<3; j++)

r.elem (i)+ = m.elem (i,j)* v.elem (j);

}

return r;

}

Способ неэффективен, так как приходится многократно вызывать функ-

цию elem.

Если бы функция multiply была функцией-членом класса vector, то можно было бы без функции elem обращаться к элементам класса vector. Аналогично, если бы функция multiply была функцией-членом класса matrix. Обратиться одновременно к закрытым элементам нескольких классов может только дружественная функция.

Способ 2. При помощи дружественной функции: class vector {

int v[4]; ….. public:

friend vector multiply (matrix&, vectot&);

}

class matrix { int v[4][4];

…..

public:

friend vector multiply (matrix&, vector&);

}

vector multiply (matrix &m, vector &v){ vector r:

for (inti=0; i<=3; i++)

14

{ r.v [i] = 0;

for (int j=0; j<=3; j++) r.v[i]+= m.v[i][j]*v.v[j];

}

return r;}

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

Функция-член одного класса может быть другом другого класса. Пример:

class x // дружественная для класса y.

{

void f ();

}; class y{

….

friend void x :: f ();

};

Рассмотрим подробнее функции дружественных классов. При таком задании все функции-члены одного класса могут являться друзьями другого класса.

class x {…}; class y { ….

friend class x;

….

};

Есть класс x и класс y, причем класс x является дружественным для класса y. Объявление класса дружественным предполагает, что закрытые и защищенные члены класса y могут использоваться в классе x.

4. УТОЧНЕНИЕ ИМЕНИ ЭЛЕМЕНТА

Иногда полезно различать имена элементов класса и просто имена. Для этого используется операция двойное двоеточие (::) – разрешение области видимости.

15

Пример: class x{

int m; public:

int readm () {return x :: m;} void setm (int m)

{x :: m = m;}

};

В функции x::setm() имя аргумента m скрывает элемент m, так что ссылаться на него можно только по уточненному имени x::m. Левым операндом (::) должно быть имя класса, если используется имя :: fun – это имя должно быть глобальным.

Наиболее часто такая запись применяется для того, чтобы использовать имена общеизвестных функций (printf, open) как имена функций-членов.

Пример: class my_file

{

public:

int open (char *, char *);

}

int my_file :: open (char * name, char * spee)

{

if (:: open (name, flag)) {…}

};

5. СТАТИСТИЧЕСКИЕ ЭЛЕМЕНТЫ КЛАССА

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

16

Пример: реализации списка всех задач. class task

{

task *next;

static task *task_chain; void schedule (int); void wait (event);

};

Описание task_chain как статического элемента обеспечивает условие, что цепочка задач будет всего одна, а не по одной копии на каждый объект task. Переменная находится в области действия класса task, обратиться извне к ней нельзя (только объявив как public).

Использование статических объектов сокращает потребность глобальных переменных.

6. ПОДСТАВЛЯЕМЫЕ ИЛИ INLINE-ФУНКЦИИ

Причина введения таких функций состоит в повышении эффективности работы программы. «Стоимость» вызова коротких, часто встречающихся функций высока, так как необходимо затратить память под переменные, передачу параметров в стэк и т. д. Такие функции объявляют подставляемыми. inline intif (void)

{…}

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

Пример:

#include <iostream.h> class cl

{

int i;

public: intget_i (void); intput_i (int j);

};

17

inline int cl :: get_i (void)

{

return i;

}

inline void cl :: put_i (int j)

{

i=j;

}

main (void)

{

cl s; s.put_i (10);

cout<<s.get_i ();

}

Ситуации, препятствующие inline кода:

наличие оператора switch, goto, операторов цикла, в случае, если функция возвращает более одного значения;

inline-функции не могут быть рекурсивными (вызывать сами себя) и содержать статические переменные;

inline-функции могут быть членами класса, могут быть обычными функциями.

Любая функция, определенная внутри шаблона класса, автоматически делается inline-функцией.

Пример:

#include <iostream.h> class cl

{

int i; public:

int get_i (void) { return i; }

intput_i (int j) {i=j; return i;}

};

18

7. ДИНАМИЧЕСКОЕ ВЫДЕЛЕНИЕ ПАМЯТИ.

ОПЕРАТОРЫ NEW, DELETE

Синтаксис: pointer_var=new type_var; delete pointer_var;

где pointer_var – указатель на переменную type_var.

Оператор new выделяет место для переменной в соответствующей области памяти и возвращает адрес выделенного места в случае успеха и NULL – если произошла ошибка. Оператор new сам определяет размер типа type_var и возвращает указатель, преобразованный к этому типу.

Выделение памяти под массив: pointer_var=new type_var [SIZE] delete [SIZE] pointer_var;

SIZE можно опустить, компилятор знает объем выделенной памяти. Пример:

main (void)

{

int *p; p=new int; if (!p)

{

cout<<”Памяти недостаточно\n”; return 1;

}

….

*p=20;

cout<<p; delete p; return 0;

}

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

19

Пример:

#include <iostream.h> main (void)

{

int *p; unsigned int size;

cout <<"Введите длину массива ;" cin >> size;

p=new int [SIZE]; if (! p){

cout<< “Недостаточно памяти;” return 1;

}

for (int i=0; i<size; i++){ p[i] _i *i; cout<<p[i];

}

delete p;

}

8. ПЕРЕГРУЖЕННЫЕ ФУНКЦИИ OVERLOADING

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

В С есть стандартные функции преобразования строки в число типа int, float, long (atoi, atof, atoll). В С++ есть аналог этих функций – перегруженная функция atonum для всех типов числовых данных.

Пример:

#include <iostream.h> int sqr_it (int i);

float sqr_it (float d); long sqr_it (long l);

20

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]