Пропавшие без вести явного ключевого слова

Конструктор, пропускающий спецификатор explicit

Описание

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

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

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

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

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

Риск

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

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

Фиксация

Для лучшей удобочитаемости вашего кода и предотвратить неявные преобразования, в объявлении конструктора, помещают ключевое слово 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
}

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

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

Введенный в R2015b