Missing explicit keyword

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

Описание

Этот дефект возникает, когда объявление или определение в классе конструктора или пользовательского оператора преобразования не использует explicit спецификатор. The 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, Day и Year не имеют explicit ключевое слово. Они допускают неявное преобразование из int переменные в Month, Day и Year переменные.

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

Коррекция - Использование explicit Ключевое слово

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

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

  • Если вы вызываете Date конструктор с аргументами, явно преобразованными в Month, Day и 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