Главная->Інформатика та програмування->Содержание->Предотвращение преобразования типов с помощью explicit

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 8) онлайн

Предотвращение преобразования типов с помощью explicit

Преобразование, которое вы решили осуществить, может быть каким-то очень специальным. И вы начинаете его осуществлять, устанавливая подходящие операции преобразования и конструкторы с одним аргументом, как это показано в примерах TIMES1 и TIMES2. Однако могут появляться другие преобразования, которые вы не хотите делать. И вы активно препятствуете их осуществлению, чтобы предотвратить неприятные сюрпризы.

Легко предотвратить выполнение операции преобразования: вы можете прос- то не определять этой операции. Но с конструкторами не все так просто. Вам может понадобиться сконструировать объекты с использованием одного значе- ния другого типа, при этом вы не хотите, чтобы осуществилось скрытое преоб- разование с помощью конструктора с одним аргументом. Что же делать?

В стандарт языка C++ включено ключевое слово explicit, предназначенное для решения этой проблемы. Оно просто помещается перед объявлением конст- руктора с одним аргументом. В программе EXPLICIT (основанной на программе ENGLCON) показано, как это выглядит.

// explicit.cpp

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class Distance

{

  private:

    const float MTF;

    int feet;

    float inches;

  public:

    Distance ( ) : feet ( 0 ), inches ( 0.0 ), MTF ( 3.280833F )

      { }

    explicit Distance ( float meters ) : MTF ( 3.280833F )

      {

        float fltfeet = MTF * meters;

        feet = int ( fltfeet );

        inches = 12 * ( fltfeet – feet );

      }

    void showdist ( )

      { cout << feet << "\'-" << inches << '\"'; }

};

///////////////////////////////////////////////////////////

int main ( )

{

  void fancyDist ( Distance );

  Distance  dist1 ( 2.35F );

 

  // Distance dist1 = 2.35F;

  cout << "\ndist1 = "; dist1.showdist ( );

 

  float mtrs = 3.0F;

  cout << "\nDist1 ";

  // fancyDist ( mtrs );

 

return 0;

}

///////////////////////////////////////////////////////////

void fancyDist ( Distance d )

{

  cout << "(в футах и дюймах) = ";

  d.showdist ( );

  cout << endl;

}

 

Эта программа включает в себя функцию fancyDist(), которая оформляет вы- вод объекта класса Distance, печатая фразу «в футах и дюймах» перед цифрами значений футов и дюймов. Аргументом этой функции является переменная класса Distance, и вы можете вызвать функцию fancyDist() с такой переменной без проблем.

Хитрость этой функции в том, что вы можете также вызывать функцию fancyDist() с переменной типа float в качестве аргумента:

fancyDist ( mtrs );

Компилятор поймет, что тип аргумента неверен и будет искать операцию преобразования. Найдя конструктор Distance, который принимает в качестве ар- гумента переменную типа float, компилятор приспособит этот конструктор для преобразования типа float в Distance и передаст значение типа Distance в функ- цию. Это неявное преобразование, одно из тех, которые вы можете упустить из вида.

Однако если мы сделаем конструктор явным, то мы предупредим неявные преобразования. Вы можете проверить это, удалив символ комментария из вызо- ва функции fancyDist() в программе: компилятор сообщит вам о том, что не может выполнить преобразование. Без ключевого слова explicit этот вызов работает.

Отметим такой побочный эффект явного конструктора, как то, что вы не може- те использовать инициализацию объекта, в которой присутствует знак равенства

Distance dist1 = 2.35F; тогда как выражение со скобками Distance dist1 ( 2.35F ); работает как обычно.

 

32