exponenta event banner

Отсутствует явное ключевое слово

В конструкторе или определяемом пользователем операторе преобразования отсутствует 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, 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++
По умолчанию: Откл.
Синтаксис командной строки: MISSING_EXPLICIT_KEYWORD
Воздействие: Низкий
Представлен в R2015b