explicit operator int() const { return val; }

 // другие члены как прежде

};

Подобно явным конструкторам (см. раздел 7.5.4), компилятор не будет (обычно) использовать явный оператор преобразования для неявных преобразований:

SmallInt si = 3; // ok: конструктор класса SmallInt не является явным

si + 3; // ошибка: нужно неявное преобразование, но оператор int

        // является явным

static_cast(si) + 3; // ok: явный запрос преобразования

Если оператор преобразования является явным, такое преобразование вполне можно осуществить. Но за одним исключением такое приведение следует осуществить явно.

Исключение состоит в том, что компилятор применит явное преобразование в выражении, используемом как условие. Таким образом, явное преобразование будет использовано неявно для преобразования выражения, используемого как:

• условие оператора if, while или do;

• выражение условия в заголовке оператора for;

• операнд логического оператора NOT (!), OR (||) или AND (&&);

• выражение условия в условном операторе (?:).

Преобразование в тип bool

В прежних версиях библиотеки типы ввода-вывода определяли преобразование в тип void*. Это было сделано во избежание проблем, описанных выше. По новому стандарту библиотека ввода-вывода определяет вместо этого явное преобразование в тип bool.

Всякий раз, когда потоковый объект используется в условии, применяется оператор operator bool(), определенный для типов ввода-вывода. Например:

while (std::cin >> value)

Условие в операторе while выполняет оператор ввода, который читает в переменную value и возвращает объект cin. Для обработки условия объект cin неявно преобразуется функцией преобразования istream::operator bool(). Эта функция возвращает значение true, если флагом состояния потока cin является good (см. раздел 8.1.2), и false в противном случае.

Преобразование в тип bool обычно используется в условиях. В результате оператор operator bool обычно должен определяться как явный.

Упражнения раздела 14.9.1

Упражнение 14.45. Напишите операторы преобразования для преобразования объекта класса Sales_data в значения типа string и double. Какие значения, по-вашему, должны возвращать эти операторы?

Упражнение 14.46. Объясните, является ли определение этих операторов преобразования класса Sales_data хорошей идеей и должны ли они быть явными.

Упражнение 14.47. Объясните различие между этими двумя операторами преобразования:

struct Integral {

 operator const int();

 operator int() const;

};

Упражнение 14.48. Должен ли класс из упражнения 7.40 раздела 7.5.1 использовать преобразование в тип bool. Если да, то объясните почему и укажите, должен ли оператор быть явным. В противном случае объясните, почему нет.

Упражнение 14.49. Независимо от того, хороша ли эта идея, определите преобразование в тип bool для класса из предыдущего упражнения.

<p><image l:href="#books.png"/>14.9.2. Избегайте неоднозначных преобразований</p>

Если у класса есть один или несколько операторов преобразования, важно гарантировать наличие только одного способа преобразования из типа класса в необходимый тип. Если будет больше одного способа осуществления преобразования, то будет весьма затруднительно написать однозначный код.

Есть два случая, когда возникает несколько путей осуществления преобразования. Первый — когда два класса обеспечивают взаимное преобразование. Например, взаимное преобразование осуществляется тогда, когда класс А определяет конструктор преобразования, получающий объект класса B, а класс в определяет оператор преобразования в тип А.

Второй случай возникновения нескольких путей преобразования — определение нескольких преобразований в и из типов, которые сами связаны преобразованиями. Самый очевидный пример — встроенные арифметические типы. Каждый класс обычно должен определять не больше одного преобразования в или из арифметического типа.

Обычно не следует определять классы со взаимными преобразованиями или определять преобразования в или из арифметических типов.

Распознавание аргумента и взаимные преобразования

В следующем примере определены два способа получения объекта класса А из В: либо при помощи оператора преобразования класса В, либо при помощи конструктора класса А, получающего объект класса В:

// обычно взаимное преобразование между двумя типами - плохая идея

struct B;

struct А {

 А() = default;

 A(const В&); // преобразует В в A

 // другие члены

};

Перейти на страницу:

Похожие книги