Язык программирования C++ для профессионалов

       

Операции преобразования


Конструктор удобно использовать для преобразования типа, но возможны нежелательные последствия:

  1. Неявные преобразования от пользовательского типа к основному невозможны (поскольку основные типы не являются классами).
  2. Нельзя задать преобразование из нового типа в старый, не изменяя описания старого типа.
  3. Нельзя определить конструктор с одним параметром, не определив тем самым и преобразование типа.

Последнее не является большой проблемой, а первые две можно преодолеть, если определить операторную функцию преобразования для исходного типа. Функция-член X::operator T(), где T - имя типа, определяет преобразование типа X в T. Например, можно определить тип tiny (крошечный), значения которого находятся в диапазоне 0..63, и этот тип может в арифметических операциях практически свободно смешиваться с целыми:

class tiny { char v; void assign(int i) { if (i>63) { error("выход из диапазона"); v=i&~63; } v=i; } public: tiny(int i) { assign(i) } tiny(const tiny& t) { v = t.v; } tiny& operator=(const tiny& t) { v = t.v; return *this; } tiny& operator=(int i) { assign(i); return *this; } operator int() { return v; } };

Попадание в диапазон проверяется как при инициализации объекта tiny, так и в присваивании ему int. Один объект tiny можно присвоить другому без контроля диапазона. Для выполнения обычных операций с целыми для переменных типа tiny определяется функция tiny::operator int(), производящая неявное преобразование типа из tiny в int. Там, где требуется int, а задана переменная типа tiny, используется преобразованное к int значение:

void main() { tiny c1 = 2; tiny c2 = 62; tiny c3 = c2 -c1; // c3 = 60 tiny c4 = c3; // контроля диапазона нет (он не нужен) int i = c1 + c2; // i = 64 c1 = c2 + 2 * c1; // выход из диапазона: c1 = 0 (а не 66) c2 = c1 - i; // выход из диапазона: c2 = 0 c3 = c2; // контроля диапазона нет (он не нужен) }

Более полезным может оказаться вектор из объектов tiny, поскольку он позволяет экономить память. Чтобы такой тип было удобно использовать, можно воспользоваться операцией индексации [].

Пользовательские операции преобразования типа могут пригодиться для работы с типами, реализующими нестандартные представления чисел (арифметика с основанием 100, арифметика чисел с фиксированной точкой, представление в двоично-десятичной записи и т.д.). При этом обычно приходится переопределять такие операции, как + и *.

Особенно полезными функции преобразования типа оказываются для работы с такими структурами данных, для которых чтение (реализованное как операция преобразования) является тривиальным, а присваивание и инициализация существенно более сложные операции.

Функции преобразования нужны для типов istream и ostream, чтобы стали возможными, например, такие операторы:



Содержание раздела