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>
#include <string>
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 - печатную книгу. С помощью операторов преобразования можно преобразовать объект одного типа в другой и наборот, то есть, грубо говоря оцифровать или распечатать книгу. Чтобы не было зацикленных ссылок одного класса на другой, здесь реализация операторов преобразования отделена от объявления.