Программирование >>  Инициализация объектов класса, структура 

1 ... 255 256 257 [ 258 ] 259 260 261 ... 395


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. Шаблоны классов



1 ... 255 256 257 [ 258 ] 259 260 261 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика