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