explicit 關鍵字僅用於修飾類的構造函數聲明,作用是抑制隱式類型轉換,強制要求顯式構造。
class Circle {
public:
Circle(double r) : R(r) {} // 單參數
Circle(int x, int y = 0) : X(x), Y(y) {} // 含預設參數,實際可單參數調用
Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {} // 拷貝構造
private:
double R; int X, Y;
};
int main() {
Circle A = 1.23; // 隱式:Circle tmp(1.23); Circle A(tmp); tmp.~Circle();
Circle B = 123; // 隱式調用 Circle(int, int=0)
Circle C = A; // 隱式調用拷貝構造
return 0;
}
class Circle {
public:
explicit Circle(double r) : R(r) {}
explicit Circle(int x, int y = 0) : X(x), Y(y) {}
explicit Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {}
// ...
};
int main() {
// Circle A = 1.23; // 編譯錯誤
// Circle B = 123; // 編譯錯誤
// Circle C = A; // 編譯錯誤(拷貝構造也被 explicit 修飾)
Circle A(1.23); // OK:直接初始化
Circle B = Circle(1.23); // OK:顯式轉換
Circle C(A); // OK:顯式調用拷貝構造
return 0;
}
| 規則 | 說明 |
|---|---|
| 位置 | 僅能出現在類內部的構造函數聲明處;定義處(類外)加會報錯 |
| 適用對象 | 單參數構造函數、含預設參數的多參數構造函數、拷貝/移動構造函數(C++11) |
| 不影響 | 顯式構造(直接初始化、顯式轉換、static_cast) |
預設為所有單參數構造函數加上 explicit,除非確有必要支持隱式轉換(如智能指針、包裝類型)。
理由:
Foo f = 42; 隱含轉換,Foo f(42); 明確表達意圖C++11 允許 explicit 修飾拷貝/移動構造函數。效果:
class Widget {
public:
explicit Widget(const Widget&); // 禁止隱式拷貝
};
Widget w1;
Widget w2 = w1; // 錯誤
Widget w3(w1); // OK
Widget w4 = Widget(w1); // OK
適用於禁止隱式拷貝的場景(如獨享所有權類型),但會導致無法用 ={...} 初始化,需權衡。
explicit 是 C++ 類型安全的重要工具。現代 C++ 風格指南(如 Google、LLVM、C++ Core Guidelines)均建議:構造函數預設加 explicit,需要隱式轉換時再移除並添加註釋說明理由。這能從語言層面消除一大類隱式轉換 Bug。