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

Последнее обновление: 13.03.2023

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

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850