C++隱式類類型轉(zhuǎn)換及explicit關(guān)鍵字的使用

1. 隱式類型轉(zhuǎn)換

C/C++中基本類型的自動類型轉(zhuǎn)換是經(jīng)常見到的情形, 例如下邊的代碼:

int i ;
float j ;
......
j = i;

其實(shí),這就是一種隱式類型轉(zhuǎn)換。當(dāng)把整形的 i 賦值給浮點(diǎn)型的 j 時黄橘,編譯器自動完成了轉(zhuǎn)換。 有了隱式類型轉(zhuǎn)換屈溉,我們少寫了很多代碼塞关,省去了不少麻煩。

2. 隱式類類型轉(zhuǎn)換

C++的類可以看作一種用戶自定義的數(shù)據(jù)類型子巾。既然和基本數(shù)據(jù)類型一樣帆赢,C++類也是一種數(shù)據(jù)類型小压,那么讓C++類支持隱式類型轉(zhuǎn)換就成了一種自然而然的想法。

在C++規(guī)則中, 可以調(diào)用單個實(shí)參的構(gòu)造函數(shù)定義了從形參類型到該類類型的一個隱式轉(zhuǎn)換椰于。
例如下邊的代碼:

class Student
{
public: 
    Student() { }
    Student(int age) { }
};

class Teacher
{
public:
    Teacher() { }
    Teacher(int age, string name="unkown") { }  
};

Student類的構(gòu)造函數(shù)僅需要一個實(shí)參就能構(gòu)造對象怠益。Teacher類的構(gòu)造函數(shù)有兩個參數(shù),但是由于第二個參數(shù)提供了默認(rèn)值瘾婿,也可以通過一個參數(shù)構(gòu)造對象蜻牢。因此,按照C++規(guī)則偏陪,這兩個類的構(gòu)造函數(shù)都實(shí)現(xiàn)了隱式轉(zhuǎn)換功能抢呆。
所以下邊的代碼也就完全可以編譯通過了:

Student foo;
Teacher bar;

foo = 12;    //隱式轉(zhuǎn)換
bar = 40;    //隱式轉(zhuǎn)換

上述的隱式類型轉(zhuǎn)換同樣由編譯器完成,編譯器通過構(gòu)造函數(shù)構(gòu)造出一個臨時對象笛谦,并將其復(fù)制為foo和bar抱虐。

這樣用起來似乎和基本類型的自動轉(zhuǎn)換一樣的爽快, 省去了好多代碼揪罕。然而梯码,凡事總是有兩面性,越是便利性的東西好啰,往往越容易犯錯。你怎么能夠總是保證編譯器幫你構(gòu)造出來的代碼就是你想要實(shí)現(xiàn)的邏輯呢儿奶?一旦出現(xiàn)代碼拼寫錯誤框往,代碼實(shí)現(xiàn)和自己的邏輯不符,而編譯器又不報錯闯捎,Debug時將加倍地費(fèi)時費(fèi)力椰弊。

關(guān)于隱式類類型轉(zhuǎn)換的缺點(diǎn),網(wǎng)上流傳比較廣泛的是如下的兩個例子:

例1:拼寫錯誤
Array<int> a[10];
Array<init>b[10];
for(int i=0;i<10;i++) {
     if(a==b[i]) {        //原意是a[i],現(xiàn)在出現(xiàn)了錯誤
                              //發(fā)生點(diǎn)什么
      }
}

這個例子中省略了一部分代碼瓤鼻,原文請參閱參考文檔[1].

簡單講秉版,由于Array類中定義了一個可以只接收一個整形參數(shù)的構(gòu)造函數(shù), 因此在if(a==b[i])發(fā)生拼寫錯誤的情況下茬祷, 編譯器并不會報錯清焕,而是自動的從b[i]隱式轉(zhuǎn)換出一個Array類型的臨時對象,并同a進(jìn)行比較祭犯。

例2:邏輯錯誤
// A simple class
class A {};

// Another simple class with a single-argument constructor for class A
class B
{
public:
    B() {}
    B(A const&) {}
};

// A function that expects a 'B'
void f(B const&) {}

int main()
{
    A obj;
    f(obj); // Spot the deliberate mistake
}

這個例子說邏輯錯誤似乎有點(diǎn)牽強(qiáng)秸妥,因為有人會講,我本來的邏輯就是要通過A類的對象構(gòu)造出來一個B類的對象沃粗,然后給f()函數(shù)使用粥惧。好吧,如果是這樣最盅,我們至少可以說邏輯不夠嚴(yán)謹(jǐn)吧突雪。至少大部分讀代碼的人會感到詫異起惕,我們要讓f()函數(shù)要處理的是一個B類對象,但是卻給了它一個A類的對象作為參數(shù)咏删,而且代碼編譯是完全沒有問題的疤祭。

之所以代碼編譯不出問題是因為B類包含了一個可以接受A類對象引用值作為參數(shù)的構(gòu)造函數(shù),滿足了隱式轉(zhuǎn)換規(guī)則饵婆。所以當(dāng)我們把A類對象obj作為參數(shù)送給f()函數(shù)時勺馆,編譯器調(diào)用了隱式轉(zhuǎn)換規(guī)則,生成了一個臨時的B類對象并傳遞給f()函數(shù)侨核。上述例子的完整表述草穆,可以參閱參考文檔[2].

你可能會想,隱式轉(zhuǎn)換也太強(qiáng)大了吧搓译,問題是悲柱,你是否能夠保證每次都是你有意寫出的代碼,而不是無心插柳些己?

3. Google C++編程規(guī)范對隱式類型轉(zhuǎn)換的建議

關(guān)于隱式類型轉(zhuǎn)換的優(yōu)缺點(diǎn)豌鸡,Google C++編程規(guī)范有詳細(xì)的描述。 其優(yōu)點(diǎn)就是語法簡潔段标,省事兒涯冠。缺點(diǎn)就比較多了:

  • 容易隱藏類型不匹配的錯誤;
  • 代碼更難閱讀逼庞;
  • 接收單個參數(shù)的構(gòu)造方法可能會意外地被用做隱式類型轉(zhuǎn)換蛇更;
  • 不能清晰地定義那種類型在何種那個情況下應(yīng)該被隱式轉(zhuǎn)換,從而使代碼變得晦澀難懂赛糟。

Google的結(jié)論就是可接收單個參數(shù)的構(gòu)造函數(shù)必需要加上explicit標(biāo)記派任,禁止隱式類類型轉(zhuǎn)換 (復(fù)制和移動構(gòu)造函數(shù)除外,因為這兩者不執(zhí)行類型轉(zhuǎn)換)璧南。

按照Google編程規(guī)范掌逛,上述例子中可接收單個參數(shù)的構(gòu)造函數(shù)都應(yīng)該聲明為如下形式。

class Student
{
public: 
    Student() { }
    explicit Student(int age) { }
};

class Teacher
{
public:
    Teacher() { }
    explicit Teacher(int age, string name="unkown") { } 
};

這樣將會禁止類類型的隱式轉(zhuǎn)換司倚,編譯器在編譯類似代碼時會直接報錯豆混,提醒開發(fā)人員檢查自己的代碼是否符合邏輯。

參考文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末对湃,一起剝皮案震驚了整個濱河市崖叫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拍柒,老刑警劉巖心傀,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拆讯,居然都是意外死亡脂男,警方通過查閱死者的電腦和手機(jī)养叛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宰翅,“玉大人弃甥,你說我怎么就攤上這事≈希” “怎么了淆攻?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嘿架。 經(jīng)常有香客問我瓶珊,道長,這世上最難降的妖魔是什么耸彪? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任伞芹,我火速辦了婚禮,結(jié)果婚禮上蝉娜,老公的妹妹穿的比我還像新娘唱较。我一直安慰自己,他們只是感情好召川,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布南缓。 她就那樣靜靜地躺著,像睡著了一般扮宠。 火紅的嫁衣襯著肌膚如雪西乖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天坛增,我揣著相機(jī)與錄音,去河邊找鬼薄腻。 笑死收捣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的庵楷。 我是一名探鬼主播罢艾,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尽纽!你這毒婦竟也來了咐蚯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤弄贿,失蹤者是張志新(化名)和其女友劉穎春锋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體差凹,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡期奔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年侧馅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呐萌。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡馁痴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肺孤,到底是詐尸還是另有隱情罗晕,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布赠堵,位于F島的核電站小渊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏顾腊。R本人自食惡果不足惜粤铭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杂靶。 院中可真熱鬧梆惯,春花似錦、人聲如沸吗垮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烁登。三九已至怯屉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饵沧,已是汗流浹背锨络。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狼牺,地道東北人羡儿。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像是钥,于是被迫代替她去往敵國和親掠归。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容