Для чего используется ключевое слово explicit в C++?

«Для чего используется ключевое слово explicit в C++?» — вопрос из категории C++ Core, который задают на 34% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Проблема, которую решает explicit: Без explicit конструктор с одним параметром (или с несколькими, где все параметры, кроме одного, имеют значения по умолчанию) становится конструктором преобразования.

class StringWrapper {
    std::string data;
public:
    // Конструктор преобразования (неявный)
    StringWrapper(const char* str) : data(str) {}
};

void printWrapper(const StringWrapper& sw) { /* ... */ }

int main() {
    StringWrapper sw = "Hello"; // Неявно: const char* -> StringWrapper (вызов конструктора)
    printWrapper("World");       // То же самое! Неявное преобразование аргумента.
}

Решение с explicit:

class StringWrapper {
    std::string data;
public:
    // Явный конструктор
    explicit StringWrapper(const char* str) : data(str) {}
};

void printWrapper(const StringWrapper& sw) { /* ... */ }

int main() {
    // StringWrapper sw = "Hello"; // ОШИБКА КОМПИЛЯЦИИ: неявное преобразование запрещено
    StringWrapper sw("Hello");     // OK: явный вызов конструктора
    StringWrapper sw2 = StringWrapper("Hello"); // OK: явное создание временного объекта

    // printWrapper("World");      // ОШИБКА КОМПИЛЯЦИИ
    printWrapper(StringWrapper("World")); // OK: явное преобразование
}

Когда использовать explicit:

  • Практически всегда для конструкторов с одним параметром, если нет веской причины разрешать неявные преобразования.
  • Это повышает безопасность и ясность кода, заставляя программиста явно указывать намеренное преобразование типа, что помогает избежать скрытых ошибок.