13.11 – Перегрузка операторов преобразования типов данных

Добавлено 19 июля 2021 в 17:29

В уроке «8.5 – Явное преобразование (приведение) типов данных и static_cast» вы узнали, что C++ позволяет преобразовывать один тип данных в другой. В следующем примере показано преобразование int в double:

int n{ 5 };
auto d{ static_cast<double>(n) }; // преобразование int в double

C++ уже умеет преобразовывать встроенные типы данных. Однако он не знает, как преобразовывать какой-либо из наших пользовательских классов. Вот здесь и вступает в игру перегрузка операторов приведения типов.

Пользовательские преобразования позволяют нам преобразовать наш класс в другой тип данных. Взгляните на следующий класс:

class Cents
{
private:
    int m_cents;
public:
    Cents(int cents=0)
        : m_cents{ cents }
    {
    }
 
    int getCents() const { return m_cents; }
    void setCents(int cents) { m_cents = cents; }
};

Этот класс довольно прост: он содержит какое-то количество центов в виде числа int и предоставляет функции доступа для получения и установки количества центов. Также он предоставляет конструктор для преобразования int в Cents.

Если мы можем преобразовать int в Cents, то, возможно, будет полезно иметь возможность преобразовывать Cents обратно в int? В некоторых случаях это может быть не так, но в данном случае это имеет смысл.

В следующем примере мы должны использовать getCents() для преобразования нашей переменной Cents обратно в число int, чтобы мы могли распечатать ее с помощью printInt():

void printInt(int value)
{
    std::cout << value;
}
 
int main()
{
    Cents cents{ 7 };
    printInt(cents.getCents()); // напечатает 7
 
    std::cout << '\n';
 
    return 0;
}

Если мы уже написали много функций, которые принимают числа int в качестве параметров, наш код будет завален вызовами getCents(), что сделает его более беспорядочным, чем нужно.

Чтобы упростить задачу, мы можем предоставить пользовательское преобразование, перегрузив приведение типа в int. Это позволит нам напрямую преобразовать наш класс Cents в тип int. В следующем примере показано, как это делается:

class Cents
{
private:
    int m_cents;
public:
    Cents(int cents=0)
        : m_cents{ cents }
    {
    }
 
    // перегруженное приведение в int
    operator int() const { return m_cents; }
 
    int getCents() const { return m_cents; }
    void setCents(int cents) { m_cents = cents; }
};

Следует отметить три вещи:

  1. Чтобы перегрузить функцию, которая приводит наш класс к типу int, мы пишем в нашем классе новую функцию с именем operator int(). Обратите внимание, что между словом operator и типом, к которому мы выполняем преобразование, есть пробел.
  2. Пользовательские преобразования не принимают параметров, так как нет возможности передать им аргументы.
  3. Пользовательские преобразования не имеют возвращаемого типа. C++ предполагает, что вы вернете правильный тип.

Теперь в нашем примере мы можем вызвать printInt() следующим образом:

int main()
{
    Cents cents{ 7 };
    printInt(cents); // напечатает 7
 
    std::cout << '\n';
 
    return 0;
}

Компилятор сначала заметит, что функция printInt принимает параметр типа int. Затем он заметит, что переменная cents не является int. Наконец, он станет проверять, предоставили ли мы способ преобразования Cents в int. Поскольку этот способ у нас есть, он вызовет нашу функцию operator int(), которая возвращает int, и возвращенный int будет передан в printInt().

Теперь мы также можем явно преобразовать нашу переменную Cents в int:

Cents cents{ 7 };
int c{ static_cast<int>(cents) };

Вы можете предоставить пользовательские преобразования в любой тип данных, который захотите, включая ваши собственные пользовательские типы данных!

Вот новый класс под названием Dollars, который обеспечивает перегруженное преобразование в Cents:

class Dollars
{
private:
    int m_dollars;
public:
    Dollars(int dollars=0)
        : m_dollars{ dollars }
    {
    }
 
     // позволяет нам преобразовывать Dollars в Cents
     operator Cents() const { return Cents{ m_dollars * 100 }; }
};

Это позволяет нам преобразовывать объект Dollars напрямую в объект Cents! Это позволяет делать что-то вроде этого:

#include <iostream>
 
class Cents
{
private:
    int m_cents;
public:
    Cents(int cents=0)
        : m_cents{ cents }
    {
    }
 
    // перегруженное преобразование в int
    operator int() const { return m_cents; }
 
    int getCents() const { return m_cents; }
    void setCents(int cents) { m_cents = cents; }
};
 
class Dollars
{
private:
    int m_dollars;
public:
    Dollars(int dollars=0)
        : m_dollars{ dollars }
    {
    }
 
    // позволяет нам преобразовывать Dollars в Cents
    operator Cents() const { return Cents(m_dollars * 100); }
};
 
void printCents(Cents cents)
{
    std::cout << cents; // cents будет здесь неявно преобразован в int
}
 
int main()
{
    Dollars dollars{ 9 };
    printCents(dollars); // dollars будет здесь неявно преобразован в Cents
 
    std::cout << '\n';
 
    return 0;
}

Следовательно, эта программа напечатает значение:

900

что имеет смысл, так как 9 долларов – это 900 центов!

Теги

C++ / CppLearnCppДля начинающихОбучениеОператор (программирование)Перегрузка (программирование)Перегрузка операторовПриведение типовПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.