Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

}

int matr::operator()(int i)

{if (i<0 || i>=a*b)

{cerr<<"выход за пределы массива ";

return **m;

// как и выше возврат m[0][0]

}

 

return m[i/b][i%b];

// возврат требуемого элемента

}

 

int main()

{ matr mt(3,5);

cout << mt(2,3) << endl;

 

 

 

 

 

 

 

cout << mt(3,2) << endl; // попытка получить элемент из 3-й строки

cout << mt(3) << endl;

 

 

 

 

 

 

Р

 

 

 

 

 

И

return 0;

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

У

 

Результаты работы программы:

 

 

 

 

 

 

 

 

Г

 

 

13

 

 

 

 

 

выход за пределы массива 0

 

 

 

 

 

 

 

 

Б

 

 

 

6

 

 

 

 

 

 

Конструктор класса matr динамичес и выделяет и инициализирует память

двухмерного массива. Деструктор разруша т

 

 

ив автоматически при завер-

 

 

масс

 

 

 

шении программы. В классе matr р ализованы

две функции operator(): первая

получает два аргумента (индексы в мат

к

 

 

 

 

 

),

вторая получает один аргумент

рице

 

 

 

 

 

(порядковый номер элемента в ма рице). Обе функции возвращают либо тре-

буемый элемент, либо элемент m[0][0] при попытке выхода за пределы матри-

цы.

 

и

т

 

 

 

л

 

 

5.2.7. Перегрузка оператора ->

 

Оператор -> доступа к компонентам объекта через указатель на него оп-

ределяется как унарный постфиксный.

 

при

 

 

 

Ниже

веден простой пример программы перегрузки оператора ->:

Б

 

 

 

 

#include <iostream>б

 

 

#include <iomanip>

 

 

using namespace std;

 

 

#include "string.h"

 

 

class cls_A

 

 

 

{ char a[40];

 

 

public:

 

 

 

 

int b;

 

 

 

 

cls_A(char *aa,int bb): b(bb)

// конструктор

{strcpy(a,aa);}

 

 

118

 

 

 

 

char *put_A() {return a;}

};

 

class cls_B

 

{ cls_A *p;

// указатель на объект класса cls_A

 

public:

 

 

 

 

 

 

 

 

 

 

 

 

cls_B(char *aa,int bb) {p=new cls_A(aa,bb);}

// конструктор

 

~cls_B() {delete p;}

 

 

 

 

 

// деструктор

 

cls_A *operator->(){return p;}

// функция перегрузки

->

 

};

 

 

 

 

 

 

 

 

 

 

Р

 

 

 

 

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

И

 

{ cls_B ptr("перегрузка оператора -> ",2);

 

 

// объект класса cls_B

 

cout << ptr->put_A() << setw(6) << ptr->b <<endl;

 

// перегрузка ->

 

cout << (ptr.operator->())->put_A() << setw(6)

 

 

 

 

 

 

<< (ptr.operator->())->b <<endl;

Г

 

 

 

 

cout << (*ptr.operator->()).put_A() << setw(6)

У

 

 

}

<< (*ptr.operator->()).b <<endl;

Б

 

 

 

 

 

 

 

 

 

а

 

 

 

 

 

 

Результат работы программы:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

перегрузка оператора ->

2

 

 

 

 

 

 

 

 

 

перегрузка оператора ->

к

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

перегрузка оператора ->

2

 

 

 

 

 

 

 

 

 

В приведенной прогр

инструкции ptr->put_A()

и

ptr->b приводят к

 

 

 

т

 

 

 

 

 

 

 

 

 

перегрузке операции ->, . . позволяют получить адрес указателя на компненты

класса cls_A для (из) объекаммеа ptr. Таким образом, инструкция ptr->b соответст-

 

 

о

 

 

 

 

 

 

 

 

 

вует инструкции (ptr.p)->b. Следующие далее две группы инструкций также

 

 

ци

 

 

 

 

 

 

 

 

 

 

верны, но не являются примером перегрузки оператора ->, а только приводят к

явному вызову функ и operator-> - компоненты класса cls_B.

 

В це ом доопределение оператора -> позволяет использовать ptr с одной

 

б

 

 

 

 

 

 

 

 

 

 

 

стороны как спе альный указатель (в примере для класса cls_A), а с другой

стороны как о ъект (для класса cls_B).

 

 

 

 

 

 

 

 

Специальные указатели могут быть доопределены следующим образом:

Б

cls A &operator*(){return *p;}

 

 

 

 

 

 

 

 

cls_A &operator[](int index){return p[index];}

 

 

 

 

аитакже доопределение может быть выполнено по отношению к большинству

рассмотренных ранее операций (+, ++

и др.).

 

 

 

 

 

5.2.8. Перегрузка операторов new и delete

В С++ имеются две возможности перегрузки операторов new и delete локально (в пределах класса) и глобально (в пределах программы). Эти операто- ры имеют правила переопределения, отличные от рассмотренных выше правил переопределения других операторов. Одна из причин перегрузки операторов new и delete состоит в том, чтобы придать им новые свойства, например выдачи

119

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

Оператор new можно задать в следующих формах:

<::> new <аргументы> имя_типа <инициализирующее_выражение>; <::> new <аргументы> имя_типа [ ];

Параметр «аргументы» можно использовать либо для того, чтобы разли-

чить разные версии глобальных операторов new, либо для использования их в

 

 

Р

теле функции operator. Доопределенную функцию operator new можно объя-

вить:

void *operator new(size_t t<список _аргументов>);

И

 

 

 

void *operator new[](size_t t<список _аргументов>);

Вторая форма используется для выделения памяти для массивов. Возвра- щаемое значение всегда должно иметь тип void *. Единственный обязательный

аргумент функции operator всегда должен иметь тип size_t. При этом в функцию

operator автоматически подставляется аргумент sizeof(t).

 

У

Ниже приведен пример программы, в которой использованы две глобаль-

ные перегруженные и одна локальная функции operator.

Г

#include <iostream>

 

 

 

 

 

Б

 

using namespace std;

 

 

 

 

а

 

 

#include <string.h>

 

 

 

 

 

 

void *operator new(size_t tip,int kol)

к//глобальная функция operator new

{ cout << "глобальная функция 1" <<endl;

// с одним параметром

 

return new char[tip*kol];

 

е

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void *operator new(size t tip,int n1,int n2)

 

// глобальная функция operator

 

 

 

 

 

т

 

 

 

 

 

{ cout << "глоба ьная функция 2" <<endl; // new с двумя параметрами

 

 

 

 

о

 

 

 

 

 

 

 

void *p=new char[tip*n1*n2];

 

 

 

 

 

 

}

return p;

 

и

 

 

 

 

 

 

 

 

л

 

 

 

 

 

 

 

 

class cls

 

 

 

 

 

 

 

 

{ char a[40];б

 

 

 

 

 

 

 

 

 

public:

 

 

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

 

 

cls(char *aa){ strcpy(a,aa); }

 

 

 

 

 

 

 

~cls(){}

 

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

 

 

};

void *operator new(size_t,int);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void *cls::operator new(size_t tp,int n)

// локальная функция operator

{cout << "локальная функция " <<endl; return new char[tp*n]; }

120

int main()

{cls obj("перегрузка оператора new"); float *ptr1,*ptr2,*ptr3;

ptr1=new

(5) float;

// вызов 1 глобальной функции

operator new

ptr2=new

(2,3) float;

// вызов 2 глобальной функции

operator new

ptr3=new float;

// вызов сиcтемной глобальной функции

cls *ptr4=new (3) cls("aa"); // вызов локальной функции operator new,

return 0;

// используя cls::cls("aa")

}

 

Р

Результаты работы программы:

 

глобальная функция 1

 

глобальная функция 2

 

локальная функция

 

 

 

Первое обращение ptr1=new (5) float

приводит к вызову глобальной

функции operator с одним параметром,

в

И

результате выделяется память

5*sizeof(float) байт (это соответствует массиву из пяти элементов типа float) и

 

У

Г

Б

 

адрес заносится в указатель ptr1. Второе обращение приводит к вызову функции

operator с двумя параметрами. Следующая инструкция new float приводит к вы-

зову системной функции new. Инструкция new (3) cls("aa") соответствует вызо-

ву функции operator, описанной в

л ссе cls. В функцию в качестве имени типа

передается тип созданного объ та

л

cls. Таким образом, ptr4 получает ад-

 

сса

рес массива из трех объектов класса cls.

 

Оператор delete разр шаетсякдоопределять только по отношению к клас-

су. В то же время можно заменить системную версию реализации оператора

delete на свою.

е

 

 

Доопределенную функцию operator

delete можно объявить:

 

 

и

 

t>);

 

void operator delete(voidт*p<,size_t

 

void operatorоdelete[](void *p<,size_t t>);

 

Функц я operator должна возвращать значение void и имеет один обяза-

 

б

 

 

 

тельный аргумент типа void * − указатель на область памяти, которая должна

быть осволождена. Ниже приведен пример программы с доопределением опе-

ратора delete.

 

 

 

Б

#include <iostream>

 

 

иusing namespace std;

 

 

 

#include "string.h"

 

 

 

#include "stdlib.h"

 

 

 

void *operator new(size_t tip,int kol)

// глобальная функция operator

{ cout << "глобальная функция NEW" <<endl;

return new char[tip*kol]; // вызов системной функции new

}

class cls

121

{ char a[40]; public:
cls(char *aa)
{ cout<<"конструктор класса strcpy(a,aa);

cls"<<endl;

}

~cls(){}

void *operator new(size_t,int); void operator delete(void *);

};

void *cls::operator new(size_t tip,int n) // локальная функция operator

{ cout << "локальная функция " <<endl;

 

 

 

 

Р

 

return new char[tip*n]; // вызов системной функции new

 

}

И

 

 

 

 

 

 

 

 

 

 

 

void cls::operator delete(void *p)

 

 

 

 

 

// локальная функция operator

 

{ cout << "локальная функция DELETE" <<endl;

 

У

 

 

delete p;

 

// вызов системной функции delete

 

 

 

}

 

 

 

 

 

 

 

 

 

Г

 

 

 

 

 

 

 

 

// глоб льн я функцияБoperator

 

void operator delete[](void *p)

 

{ cout << "глобальная функция DELETE" <<endl;

 

 

 

 

 

delete p;

 

// вызов сист

ной фун ции delete

 

 

 

}

 

 

 

 

 

 

 

 

а

 

 

 

 

 

 

 

 

 

 

 

к

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

ем

 

 

 

 

 

{ cls obj("перегрузка опера оров NEW и DELETE");

 

 

 

 

float *ptr1;

 

 

 

 

 

 

 

 

 

 

 

 

ptr1=new (5) float; // выз в глобальной функции доопр. оператора new

 

delete [] ptr1;

 

 

т

 

 

 

 

 

 

 

// выз в глобальной функции доопр. оператора delete

 

 

 

 

 

о

 

 

 

 

 

 

 

 

cls *ptr2=new (10) cls("aa"); // вызов локальной функции доопределения

 

delete ptr2;

 

и

// оператора new (из класса cls)

 

 

л

 

// вызов локальной функции доопределения

 

return 0;

 

// оператора delete (из класса cls)

 

}

 

б

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

 

 

 

 

Результаты работы программы: глобальная функция NEW глобальная функция DELETE локальная функция NEW конструктор класса cls локальная функция DELETE

Инструкция cls *ptr2=new (10) cls("aa") выполняется следующим образом: вначале вызывается локальная функция operator для выделения памяти, равной 10*sizeof(cls), затем вызывается конструктор класса cls.

122

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

ния delete.

Далее рассмотрим пример доопределения функций new и delete в одном из классов, содержащемся в некоторой иерархии классов.

#include <iostream> using namespace std;

class A

 

 

 

 

 

 

 

 

 

Р

{ public:

 

 

 

 

 

 

 

 

 

A(){cout<<"конструктор A"<<endl;}

 

 

 

 

 

 

 

virtual ~A(){cout<<"деструктор A"<<endl;} //виртуальный деструктор

 

void *operator new(size_t,int);

 

 

И

 

 

У

 

 

void operator delete(void *,size_t);

 

 

};

 

 

 

 

 

 

 

Г

 

 

 

 

 

 

 

 

 

Б

 

 

 

class B : public A

 

 

 

 

 

 

 

{ public:

 

 

 

 

 

 

 

 

 

B(){cout<<"конструктор В"<<endl;}

 

 

 

 

~B(){cout<<"деструктор В"<<endl;}

 

 

 

};

 

 

 

 

 

 

а

 

 

 

 

 

 

 

 

к

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void *A::operator new(size t tip,int n)

 

 

 

 

 

 

 

 

 

е

 

 

 

 

 

{ cout << "перегрузка operator NEW" <<endl;

 

 

 

 

return new char[tip*n];

 

 

 

 

 

 

}

 

 

 

т

 

 

 

 

 

 

 

 

 

 

 

 

//глобальная функция operator

void A::operator delete(void *p,size_t t)

 

 

 

о

 

 

 

 

 

 

 

{ cout << " перегрузка operator DELETE" <<endl;

 

 

 

 

и

 

// вызов глобальной (системной) функции

 

delete p;

 

 

}

л

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

 

 

{ A *ptr1=new(2) A; // вызов локальной функции, используя A::A()

иdelete ptr1;

 

 

 

 

 

 

 

 

 

A *ptr2=new(3) B; // вызов локальной функции, используя B::B()

Б delete ptr2;

 

 

 

 

 

 

 

 

}

return 0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Результаты работы программы:

 

 

 

 

перегрузка

operator NEW

 

 

 

 

 

 

конструктор A

123

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