C++ explicit 關(guān)鍵字
最近學(xué)習(xí)的過程中經(jīng)??吹?code>explicit這個關(guān)鍵字, 于是去了解了一下. 沒好好讀過C++ Primer的我只想感慨: "C++還會發(fā)生這樣的隱式類型轉(zhuǎn)換啊."
隱式類型轉(zhuǎn)換 (構(gòu)造函數(shù)的隱式調(diào)用)
先來看一下這種隱式類型轉(zhuǎn)換是怎么發(fā)生的吧.
#include <iostream>
using namespace std;
class Point {
public:
int x, y;
Point(int x = 0, int y = 0)
: x(x), y(y) {}
};
void displayPoint(const Point& p)
{
cout << "(" << p.x << ","
<< p.y << ")" << endl;
}
int main()
{
displayPoint(1);
Point p = 1;
}
我們定義了一個再簡單不過的Point類, 它的構(gòu)造函數(shù)使用了默認(rèn)參數(shù). 這時主函數(shù)里的兩句話都會觸發(fā)該構(gòu)造函數(shù)的隱式調(diào)用. (如果構(gòu)造函數(shù)不使用默認(rèn)參數(shù), 會在編譯時報錯)
顯然, 函數(shù)displayPoint需要的是Point類型的參數(shù), 而我們傳入的是一個int, 這個程序卻能成功運行, 就是因為這隱式調(diào)用. 另外說一句, 在對象剛剛定義時, 即使你使用的是賦值操作符=, 也是會調(diào)用構(gòu)造函數(shù), 而不是重載的operator=運算符.
這樣悄悄發(fā)生的事情, 有時可以帶來便利, 而有時卻會帶來意想不到的后果. explicit關(guān)鍵字用來避免這樣的情況發(fā)生.
explicit關(guān)鍵字
- 指定構(gòu)造函數(shù)或轉(zhuǎn)換函數(shù) (C++11起)為顯式, 即它不能用于隱式轉(zhuǎn)換和復(fù)制初始化.
- explicit 指定符可以與常量表達式一同使用. 函數(shù)若且唯若該常量表達式求值為 true 才為顯式. (C++20起)
這篇文章我們關(guān)注的就是第一點. 構(gòu)造函數(shù)被explicit修飾后, 就不能再被隱式調(diào)用了. 也就是說, 之前的代碼, 在Point(int x = 0, int y = 0)前加了explicit修飾, 就無法通過編譯了.
能用就用
如果我們能預(yù)料到某種情況的發(fā)生, 就不要把這個情況的控制權(quán)交給編譯器. 之前的代碼, 以前我都覺得它無法通過編譯. 在不知道explicit關(guān)鍵字的情況下, 我也是每次都使用Point(1)做一個類型轉(zhuǎn)換再傳入給displayPoint函數(shù).
Effective C++中也寫:
被聲明為
explicit的構(gòu)造函數(shù)通常比其 non-explicit 兄弟更受歡迎, 因為它們禁止編譯器執(zhí)行非預(yù)期 (往往也不被期望) 的類型轉(zhuǎn)換. 除非我有一個好理由允許構(gòu)造函數(shù)被用于隱式類型轉(zhuǎn)換, 否則我會把它聲明為explicit. 我鼓勵你遵循相同的政策.
// 加了explicit之后的代碼
#include <iostream>
using namespace std;
class Point {
public:
int x, y;
explicit Point(int x = 0, int y = 0)
: x(x), y(y) {}
};
void displayPoint(const Point& p)
{
cout << "(" << p.x << ","
<< p.y << ")" << endl;
}
int main()
{
displayPoint(Point(1));
Point p(1);
}