Missing explicit keyword

Конструктор или пользовательский оператор преобразования, пропускающий explicit спецификатор

Описание

Этот дефект происходит, когда объявление или в определении класса конструктора или пользовательского оператора преобразования не использует explicit спецификатор. explicit спецификатор предотвращает неявное преобразование из переменной другого типа к текущему типу класса.

Дефект применяется:

  • Конструкторы с одним параметром.

  • Конструкторы, где у всех кроме параметров есть значения по умолчанию.

    Например, MyClass::MyClass(float f, bool b=true){}.

  • Пользовательские операторы разговора.

    Например, operator int() {} преобразует переменную текущего типа класса к int переменная.

Риск

Если вы не объявляете конструктора или оператор преобразования explicit, компиляторы могут выполнить неявные и часто непреднамеренные преобразования типов к или от типа класса возможно неожиданными результатами.

Неявное преобразование с помощью конструктора может произойти, например, когда функция принимает параметр типа класса, но вы вызываете функцию с аргументом другого типа. Вызов func здесь вызывает неявное преобразование из типа int к myClass:

class myClass {}{
  ...
  myClass(int) {...}
};
void func(myClass);
func(0);

Противоположное неявное преобразование может произойти при использовании пользовательского оператора преобразования. Например, вы передаете тип класса в качестве аргумента, но функция имеет параметр другого типа. Вызов func здесь вызывает неявное преобразование из типа myClass к int:

class myClass {} {
  ...
  operator int() {...}
};
myClass myClassObject;

void func(int) {...}
func(myClassObject);

Фиксация

Для лучшей удобочитаемости вашего кода и предотвратить неявные преобразования, в объявлении или в определении класса конструктора или оператора преобразования, помещают explicit ключевое слово перед конструктором или именем оператора. Можно затем обнаружить все неявные преобразования как ошибки компиляции и преобразовать их в явные преобразования.

Примеры

развернуть все

class MyClass {
public:
    MyClass(int val);
private:
    int val;
};

void func(MyClass);

void main() {
    MyClass MyClassObject(0);

    func(MyClassObject);   // No conversion
    func(MyClass(0));      // Explicit conversion
    func(0);               // Implicit conversion
}

В этом примере, конструкторе MyClass не объявляется explicit. Поэтому вызов func(0) может выполнить неявное преобразование из int к MyClass.

Коррекция — использует explicit Ключевое слово

Одна возможная коррекция должна объявить конструктора MyClass как explicit. Если операция в вашем коде выполняет неявное преобразование, компилятор генерирует ошибку. Поэтому использование explicit ключевое слово, вы обнаруживаете непреднамеренные преобразования типов на этапе компиляции.

Например, в функциональном main ниже, если вы добавляете оператор func(0); это выполняет неявное преобразование, код не компилирует.

class MyClass {
public:
    explicit MyClass(int val);
private:
    int val;
};

void func(MyClass);

void main() {
    MyClass MyClassObject(0);

    func(MyClassObject);   // No conversion
    func(MyClass(0));      // Explicit conversion
}
class Month {
    int val;
public:
    Month(int m): val(m) {}
    ~Month() {}
};

class Day {
    int val;
public:
    Day(int d): val(d) {}
    ~Day() {}
};

class Year {
    int val;
public:
    Year(int y): val(y) {}
    ~Year() {}
};

class Date {
    Month mm;
    Day dd;
    Year yyyy;
public:
    Date(const Month & m, const Day & d, const Year & y):mm(m), dd(d), yyyy(y) {}
};

void main() {
    Date(20,1,2000); //Implicit conversion, wrong argument order undetected
}

В этом примере, конструкторах для классов Monthдень и Year не имейте explicit ключевое слово. Они позволяют неявное преобразование из int переменные к Monthдень и Year переменные.

Когда вы создаете Date переменная и использование неправильный порядок аргументов для Date конструктор, из-за неявного преобразования, ваших компиляций кода. Вы не можете обнаружить, что переключили значение месяца и дневное значение.

Коррекция — использует explicit Ключевое слово

Если вы используете explicit ключевое слово для конструкторов классов Monthдень и Year, вы не можете вызвать Date конструктор с неправильным порядком аргументов.

  • Если вы вызываете Date конструктор с int переменные, ваш код не компилирует потому что explicit ключевое слово предотвращает неявное преобразование из int переменные.

  • Если вы вызываете Date конструктор с аргументами, явным образом преобразованными в Monthдень и Year, и имейте неправильный порядок аргументов, ваш код не компилирует из-за несоответствия типа аргумента.

class Month {
    int val;
public:
    explicit Month(int m): val(m) {}
    ~Month() {}
};

class Day {
    int val;
public:
    explicit Day(int d): val(d) {}
    ~Day() {}
};

class Year {
    int val;
public:
    explicit Year(int y): val(y) {}
    ~Year() {}
};

class Date {
    Month mm;
    Day dd;
    Year yyyy;
public:
    Date(const Month & m, const Day & d, const Year & y):mm(m), dd(d), yyyy(y) {}
};

void main() {
    Date(Month(1),Day(20),Year(2000)); 
    // Date(20,1,2000); - Does not compile
    // Date(Day(20), Month(1), Year(2000)); - Does not compile
}
#include <cstdint>

class MyClass {
public:
    explicit MyClass(int32_t arg): val(arg) {};
    operator int32_t() const { return val; }
    explicit operator bool() const {
        if (val>0) {
          return true;
        }
        return false;
     } 
private:
    int32_t val;
};

void useIntVal(int32_t);
void useBoolVal(bool);

void func() {
    MyClass MyClassObject{0};
    useIntVal(MyClassObject); 
    useBoolVal(static_cast<bool>(MyClassObject));
}

В этом примере, оператор преобразования operator int32_t() не задан с explicit спецификатор и позволяет неявные преобразования. Оператор преобразования operator bool() задан явный.

При преобразовании в bool переменная, например, в вызове useBoolVal, explicit ключевое слово в операторе преобразования гарантирует, что необходимо выполнить явное преобразование из типа MyClass к bool. Нет такого требования при преобразовании в int32_t переменная. В вызове useIntVal, выполняется неявное преобразование.

Информация о результате

Группа: Объектно-ориентированный
Язык: C++
Значение по умолчанию: 'off'
Синтаксис командной строки: MISSING_EXPLICIT_KEYWORD
Удар: низко

Введенный в R2015b