|
Программирование >> Инициализация объектов класса, структура
class Screen { public: void *operator new[]( size t ); void *operator new[]( size t, Screen* ); void operator delete[]( void*, size t ); void operator delete[]( void*, Screen* ); ... массивов: Оператор new[]() используется в случае, когда в выражении, содержащем new для void func( Screen *start ) { вызается Screen::operator new[] ( size t, Screen* ) Screen *ps = new (start) Screen[10]; ... распределения массива, заданы соответствующие аргументы размещения: Если при работе оператора new конструктор возбуждает исключение, то автоматически вызывается соответствующий delete[]() . Упражнение 15.9 class iStack { public: iStack( int capacity ) : stack( capacity ), top( 0 ) {} ... private: int top; vatcor< int > stack; Объясните, какие из приведенных инициализаций ошибочны: void operator delete( void*, Screen* ); Если такой оператор будет найден, то он вызывается для освобождения памяти в случае, когда new() возбуждает исключение. (Иначе - не вызывается.) Разработчик класса принимает решение, предоставлять ли delete() , соответствующий некоторому new() , в зависимости от того, выделяет ли этот оператор new() память самостоятельно или пользуется уже выделенной. В нервом случае delete () необходимо включить для освобождения памяти, если конструктор возбудит исключение; иначе в нем нет необходимости. Можно также перегрузить оператор размещения new[]() и оператор delete[]() для (a) iStack *ps = new iStack(20); (b) iStack *ps2 = new const iStack(15); (c) iStack *ps3 = new iStack[ 100 ]; Упражнение 15.10 class Exercise { public: Exercise(); ~Exercise(); Exercise *pe = new Exercise[20]; Что происходит в следующих выражениях, содержащих new и delete? delete[] ps; Измените эти выражения так, чтобы вызывались глобальные операторы new() и delete() . Упражнение 15.11 Объясните, зачем разработчик класса должен предоставлять оператор delete() . 15.9. Определенные пользователем преобразования Мы уже видели, как преобразования типов применяются к операндам встроенных типов: в разделе 4.14 этот вопрос рассматривался на примере операндов встроенных операторов, а в разделе 9.3 - на примере фактических аргументов вызванной функции для приведения их к типам формальных параметров. Рассмотрим с этой точки зрения char ch; short sh;, int ival; в каждой операции один операнд требует преобразования типа */ ival; ival + ch; sh; ch + ch; ch + ch + sh; следующие шесть операций сложения: ival + sh; sh + ival; Операнды ch и sh расширяются до типа int. При выполнении операции складываются два значения типа int. Расширение типа неявно выполняется компилятором и для пользователя прозрачно. В этом разделе мы рассмотрим, как разработчик может определить собственные преобразования для объектов типа класса. Такие определенные пользователем преобразования также автоматически вызываются компилятором по мере необходимости. Чтобы показать, зачем они нужны, обратимся снова к классу SmallInt, введенному в разделе 10.9. class SmallInt { friend operator+( const SmallInt s, int friend operator-( const SmallInt s, int friend operator-( int, const SmallInt s friend operator+( int, const SmallInt s public: SmallInt( int ival ) : value( ival ) { } operator+( const SmallInt s ); operator-( const SmallInt s ); private: int value; операторных функций: Операторы-члены дают возможность складывать и вычитать два объекта SmallInt. Глобальн1е же онераторы-друзья позволяют производить эти операции над объектами данного класса и объектами встроенных арифметических типов. Необходимо только шесть операторов, поскольку любой встроенный арифметический тип может быть SmallInt si( 3 ); приведен к типу int. Например, выражение si + 3.14159 разрешается в два шага: 1. Константа 3.14159 тина double преобразуется в целое число 3. 2. Выз1вается operator+(const SmallInt s,int), который возвращает значение 6. Если мы хотим поддержать битовые и логические операции, а также операции сравнения и составные операторы присваивания, то сколько же необходимо перегрузить операторов? Сразу и не сосчитаешь. Значительно удобнее автоматически преобразовать объект класса SmallInt в объект тина int. В языке С++ имеется механизм, позволяющий в любом классе задать набор преобразований, применимых к его объектам. Для SmallInt мы определим приведение объекта к типу int. Вот его реализация: Напомним, что SmallInt позволяет определять объекты, способные хранить значения из того же диапазона, что unsigned char, т.е. от 0 до 255, и перехватывает ошибки выхода за его границы. Во всех остальных отношениях этот класс ведет себя точно так же, как unsigned char. Чтобы иметь возможность склад1вать объекты SmallInt с другими объектами того же класса или со значениями встроенных типов, а также вычитать их, реализуем шесть
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |