C++ позвляет определить функцию оператора преобразования из типа текущего класса в другой тип. Тип, в который производится преобразование, может быть фундаментальным типом или типом класса. В общем случае оператор преобразования имеет следующую форму:
class MyClass { public: operator OtherType() const; // преобразование из типа MyClass в тип OtherType .......................... };
OtherType
здесь представляет тип, в который преобразуем объект. При чем тип возвращаемого значения у функции оператора не указыватся,
поскольку целевой тип всегда подразумевается в имени функции, поэтому здесь функция должна возвращать объект OtherType.
В отличие от большинства операторов, операторы преобразования должны быть определены только как функции-члены класса. Их нельзя определить как обычные функции.
Они также являются единственными операторами, в которых ключевому слову оператора не предшествует тип возвращаемого значения (вместо этого возвращаемый тип идет после ключевого слова
operator
). Рассмотрим простейший пример:
#include <iostream> class Counter { public: Counter(int number) { value = number; } operator int() const { return value; } private: int value; }; int main() { Counter counter{25}; int n = counter; // преобразуем от Counter в int std::cout << n << std::endl; // 25 // или так int m {counter}; std::cout << m << std::endl; // 25 }
Здесь в классе Counter определен оператор преобразования в тип int:
operator int() const { return value; }
В данном случае просто возвращаем значение переменной value.
После этого можно, например, присвоить переменной или параметру типа int значение типа Counter - и такое значение будет автоматически преобразовываться в int:
Counter counter{25}; int n = counter; // преобразуем от Counter в int - n=25
Благодаря оператору преобразования подобная конвертация типов выполняется неявно. Но преобразование типов также можно выполнять явно, например, с помощью функции static_cast
Counter counter{25}; int n = static_cast<int>(counter); // явное преобразование из Counter в int std::cout << n << std::endl; // 25 // или так int m {static_cast<int>(counter)}; // явное преобразование из Counter в int std::cout << m << std::endl; // 25
Еще один пример - преобразование в тип bool
:
#include <iostream> class Counter { public: Counter(double n) { value = n; } void print() const { std::cout << "value: " << value << std::endl; } // Оператор преобразования в bool operator bool() const { return value != 0; } private: int value; }; // тестируем операторы void testCounter(const Counter& counter) { counter.print(); if (counter) std::cout << "Counter is non-zero." << std::endl; if (!counter) std::cout << "Counter is zero." << std::endl; } int main() { Counter counter1{22}; testCounter(counter1); Counter counter2{0}; testCounter(counter2); }
В данном случае в операторе преобразования, если значение value объекта Counter равно 0, возвращаем false, иначе возвращаем true:
operator bool() const { return value != 0; }
Благодаря чему мы можем использовать объект Counter в условных выражениях, подобно типу bool:
if (counter) if (!counter)
Стоит отметить, что хотя мы не определили явным образом оператор ! (оператор логического отрицания) для типа Counter, но выражение !counter
будет успешно выполняться,
потому что в данном случае объект counter
будет неявно преобразован в bool
.
Неявные преобразования не всегда могут быть желательны. В этом случае их можно отключить, определив функцию оператора с помощью ключевого слова explicit:
#include <iostream> class Counter { public: Counter(int number) { value = number; } explicit operator int() const { return value; } // Только явные преобразования private: int value; }; int main() { Counter counter{25}; int n = static_cast<int>(counter); // явное преобразование std::cout << n << std::endl; // 25 // int m = counter; // так нельзя, допустимы только явные преобразования // std::cout << m << std::endl; }
Подобным образом можно выполнять преобразования между типами классов:
#include <iostream> class PrintBook; // электронная книга class Ebook { public: Ebook(std::string book_title) { title=book_title; } operator PrintBook() const; std::string getTitle(){return title;} private: std::string title; }; // печатная книга class PrintBook { public: PrintBook(std::string book_title) { title=book_title; } operator Ebook() const; std::string getTitle(){return title;} private: std::string title; }; Ebook::operator PrintBook() const { return PrintBook{title}; } PrintBook::operator Ebook() const { return Ebook{title}; } int main() { PrintBook book{"C++"}; Ebook ebook{ book }; // оцифровываем книгу - из PrintBook в Ebook std::cout << ebook.getTitle() << std::endl; // C++ PrintBook print_book{ebook}; // распечатываем книгу из Ebook в PrintBook std::cout << print_book.getTitle() << std::endl; // C++ }
Здесь класс Ebook представляет электронную книгу, а PrintBook - печатную книгу. С помощью операторов преобразования можно преобразовать объект одного типа в другой и наборот, то есть, грубо говоря оцифровать или распечатать книгу. Чтобы не было зацикленных ссылок одного класса на другой, здесь реализация операторов преобразования отделена от объявления.