Ответ
Ключевое слово 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:
- Практически всегда для конструкторов с одним параметром, если нет веской причины разрешать неявные преобразования.
- Это повышает безопасность и ясность кода, заставляя программиста явно указывать намеренное преобразование типа, что помогает избежать скрытых ошибок.