|
Программирование >> Инициализация объектов класса, структура
String flower( tulip ); void foo( const char *pf ) { вызывается перегруженны char перегруженн оператор String::operator==() if ( flower == pf ) cout << pf << is a flower!\en ; ... Тогда при сравнении flower == pf вызывается оператор равенства класса String: String::operator==( const String & ) const; Для трансформации правого операнда pf из типа const char* в тип String параметра operator==() применяется определенное пользователем преобразование, которое вызывает конструктор: String( const char * ) class String { ... public: String( const char * = 0 bool operator= const char*(); новый конвертер bool operator== ( const String & ) const; operator const char*(); Если добавить в определение класса String конвертер в тип const char*: проверка на равенство больше не компилируется! то показанное использование operator==() становится неоднозначным: if (flower == pf) Из-за добавления конвертера operator const char*() встроенный оператор сравнения bool operator==( const char *, const char * ) тоже считается устоявшей функцией. С его помощью левый операнд flower типа String может быть преобразован в тип const char *. Теперь для использования operator==() в foo() есть две устоявших операторных функции. Первая из них String::operator==( const String & ) const; namespace NS { class complex { complex( double ); ... class LongDouble { friend LongDouble operator+( LongDouble &, int ) { /* ... */ } public: LongDouble( int ); operator double(); LongDouble operator+( const complex & ); ... LongDouble operator+( const LongDouble &, double ); int main() { NS::LongDouble ld(16.08); double res = ld + 15.05; какой operator+? return 0; устоявшей функции. требует применения определенного пользователем преобразования правого операнда pf из типа const char* в тип String. Вторая bool operator==( const char *, const char * ) требует применения пользовательского преобразования левого операнда flower из типа String в тип const char*. Таким образом, первая устоявшая функция лучше для левого операнда, а вторая - для правого. Поскольку наилучшей функции не существует, то вызов помечается компилятором как неоднозначный. При проектировании интерфейса класса, включающего объявление перегруженных операторов, конструкторов и конвертеров, следует быть весьма аккуратным. Определенные пользователем преобразования применяются компилятором неявно. Это может привести к тому, что встроенные операторы окажутся устоявшими при разрешении перегрузки для операторов с операндами типа класса. Упражнение 15.17 Назовите пять множеств функций-кандидатов, рассматриваемых при разрешении перегрузки оператора с операндами типа класса. Упражнение 15.18 Какой из операторов operator+() будет выбран в качестве наилучшего из устоявших для оператора сложения в miain() ? Перечислите все функции-кандидаты, все устоявшие функции и преобразования типов, которые надо применить к аргументам для каждой В этой главе описывается, как определять и использовать шаблоны классов. Шаблон - это предписание для создания класса, в котором один или несколько типов либо значений параметризованы. Начинающий программист может использовать шаблоны, не понимая механизма, стоящего за их определениями и конкретизациями. Фактически на протяжении всей этой книги мы пользовались шаблонами классов, которые определены в стандартной библиотеке C++ (например, vector, list и т.д.), и при этом не нуждались в детальном объяснении механизма их работа:. Только нрофессиональн1е программисты определяют собственные шаблоны классов и пользуются описанными в данной главе средствами. Поэтому этот материал следует рассматривать как введение в более сложные аспекты C++. Глава 16 содержит вводные и продвинутые разделы. Во вводных разделах показано, как определяются шаблоны классов, иллюстрируются простые способы применения и обсуждается механизм их конкретизации. Мы расскажем, как можно задавать в шаблонах разные виды членов: функции-члены, статические данные-члены и вложенные типы. В продвинутых разделах представлен материал, необходимый для написания приложений промышленного уровня. Сначала мы рассмотрим, как компилятор конкретизирует шаблоны и какие требования в связи с этим предъявляются к организации нашей программы. Затем покажем, как определять специализации и частичные специализации для шаблона класса и для его члена. Далее мы остановимся на двух вопросах, представляющих интерес для проектировщиков: как разрешаются имена в определениях шаблона класса и как можно определять шаблоны в пространствах имен. Завершается эта глава примером определения и использования шаблона класса. 16.1. Определение шаблона класса Предположим, что нам нужно определить класс, поддерживающий механизм очереди. Очередь - это структура данных для хранения коллекции объектов; они помещаются в конец очереди, а извлекаются из ее начала. Поведение очереди описывают аббревиатурой FIFO - первым пришел, первым ушел . (Определенный в стандартной библиотеке C++ тин, реализующий очередь, упоминался в разделе 6.17. В этой главе м1 создадим упрощенный тип для знакомства с шаблонами классов.) Необходимо, чтобы наш класс Queue поддерживал следующие операции: добавить элемент в конец очереди: void add( item ); удалить элемент из начала очереди: item remove(); определить, пуста ли очередь: 16. Шаблоны классов
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |