Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 [ 13 ] 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

class Function { public:

int operator()(char*);

int Function::operator()(char* s)

cout << "\"" << s << "\"";

Function fn;

int x = fn("He11o"); Выводит в cout строку "Hello"

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

Оператор new

Изобретая новый язык, приходится изобретать собственные правила. Одно из новых правил C++ гласит, что имя оператора не обязано состоять из одних служебных символов. Исключение составляют операторы new и delete. Оператор new вызывается всякий раз, когда компилятор считает, что настало время выделить из кучи память для нового объекта. Используемый здесь термин объект относится к любым динамическим данным, включая int, char* и т.д., а не только к экземплярам ваших классов. Оператор new по умолчанию имеет следующий интерфейс:

void* operator new(size t bytes);

Единственный аргумент - количество выделяемых байт, возвращаемое значение - адрес выделенной области. Оператор new никогда не должен возвращать NULL; вместо этого при нехватке памяти инициируется исключение (см. главу 4). Реализация оператора new по умолчанию изменяется от простого вызова функции mall ос или call ос до нестандартных средств управления памятью, прилагаемых к компилятору.

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

class Foo { public:

void* operator new(size t bytes);

void* Foo::operator new(size t bytes)

if (bytes < MAXBYTES)

Нестандартное выделение памяти для блоков малого размера else return ::operator new(bytes);

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

class Pool { Нестандартный пул памяти public:

virtual void* Al1ocate(size t bytes);



void* operator new(size t bytes, Pool* p)

return p->Al1ocate(bytes);

extern Pool* DefaultPool; Foo* f = new(DefaultPool) Foo;

Дополнительные аргументы указываются между ключевым словом new и перед именем класса Foo; они передаются перегруженному оператору после размера блока, предоставленного компилятором.

Оператор delete

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

1. void operator de1ete(void* address);

2. void operator de1ete(void* address, size t bytes);

Первая версия просто передает вам адрес освобождаемого блока; чтобы определить его размер, вам придется самостоятельно заглянуть в хрустальный шар. Вторая версия вроде бы передает размер освобождаемого блока, но... он может быть меньше истинного размера! Проблемы возникают в следующих ситуациях:

class Foo { private:

int x; public:

~Foo(); Невиртуальный деструктор

class Bar : public Foo { private: int y;

public:

~Bar();

Bar* b = new Bar;

delete b; Правильный размер

Foo* f = new Bar;

delete f; Размер Foo, а не Bar

Компилятор определяет размер на основании вызываемого деструктора. Если невиртуальный деструктор вызывается для указателя на базовый класс, используется размер базового класса. Правильный размер будет передаваться при соблюдении любого из трех условий:

1 . Деструктор является виртуальным.

2. Указатель ссылается на настоящий тип объекта.

3. Тип, на который ссылается указатель, имеет тот же размер, что и настоящий тип.

Последнее условие соблюдается лишь в том случае, если в производном классе не добавляется ни одной новой переменной, а базовый и производный классы одновременно либо содержат, либо не содержат виртуальных функций (и как следствие, указателей v-таблицы). Непонятно? Тогда запомните простое правило - объявляйте ваши деструкторы виртуальными.

Оператор delete, как и оператор new, можно перегружать как в форме функции класса, так и в форме внешней функции. Если оператор перегружается функцией класса, он наследуется. В отличие от



оператора new, для оператора delete нельзя создавать дополнительные сигнатуры. Два варианта, приведенные выше, - это все, что у вас есть.



0 1 2 3 4 5 6 7 8 9 10 11 12 [ 13 ] 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82