Анимация
JavaScript
|
Главная Библионтека класса. Вот реализация предыдущего производного класса для самого худшего случая: class derived : public base string s; public: derived( const derived &r ); const derived &operator=( const derived &r ); ----------------------------------------------------------- derived::derived( const derived &r ) : base(r), s(r.s) -----------------------------------------------------------const derived &derived::operator=( const derived &r ) (* (base*)this)=r; s = r.s; Список инициализации членов в конструкторе копии описан ранее. Следующий отрывок из функции operator=() нуждается в некотором пояснении: (* (base*)this)=r; Указатель this указывает на весь текущий объект; добавление оператора приведения преобразует его в указатель на компонент базового класса в текущем объекте - (base*) this. (* (base*) this) является самим объектом, а выражение (* (base*) this)=r передает этому объекту сообщение, вызывая функцию operator=() базового класса для перезаписи информации из правого операнда в текущий объект. Вы могли бы заменить этот код таким образом: base:: operator=(r); но я видел компиляторы, которые бракуют этот оператор, если в базовом классе не объявлена явно функция operator=(). Первая форма работает независимо от того, объявлена явно operator=() , или нет. (Если не объявлена, то у вас будет по умолчанию реализовано почленное копирование). Стандартом языка для этого предусмотрено ключевое слово explicit. - Ред. 1 32. Конструкторы, не предназначенные для преобразования типов, должны иметь два или более аргумента Си++ использует конструкторы для преобразования типов. Например, конструктор char* в 9-ой строке листинга 7 на странице 155 также обрабатывает следующую операцию приведения: char *pchar = "абвг"; (string) pchar; Запомните, что приведение является операцией времени выполнения, которая создает временную переменную нужного типа и инициализирует ее из аргумента. Если приводится класс, то для инициализации используется конструктор. Следующий код работает прекрасно, потому что строковая константа char* беспрепятственно преобразуется в string для передачи в функцию f() : f( const string &s ); ... f( " белиберда"); Проблема состоит в том, что мы иногда не желаем использовать конструктор для неявного преобразования типов. Рассмотрим следующий контейнер массива, которым поддерживается целочисленный конструктор, определяющий размер этого массива: class array ... public: array( int initial size ); Вероятно вы все же не захотите, чтобы следующий код работал: f( const array &a ); ... f( isupper(*str) ); (Этот вызов передает f() пустой одноэлементный массив, если *str состоит из заглавных букв, или массив без элементов, если *str - из строчных букв). Единственным способом подавления такого поведения является добавление второго аргумента в конструктор, потому что конструкторы с несколькими аргументами никогда не используются неявно: class array ... public: enum bogus { set size to }; array( bogus, int initial size ); array ar( array::set size to, 128 ); Это по настоящему уродливо, но у нас нет выбора. Заметьте, что я не дал аргументу bogus имени, потому что он используется только для выбора функции. 133. Используйте счетчики экземпляров объектов для инициализации на уровне класса Несколько разделов назад я рассматривал использование счетчика статических глобальных объектов для управления инициализациями на уровне библиотеки. В Си++ у нас есть лучшие варианты, потому что мы может использовать определение класса для ограничения области действия: class window static int num windows; public: window(); ~window(); int window::num windows = 0; window::window() if( ++num windows == 1 ) только что создано первое окно initialize video system(); window::~window() if( --num windows == 0 ) только что уничтожено shut down video system(); последнее окно Наконец, счетчик экземпляров объектов может быть также использован в качестве счетчика числа вызовов для обеспечения инициализации на уровне подпрограммы: 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 |