C++之類(lèi)型轉(zhuǎn)換函數(shù)
一、轉(zhuǎn)換構(gòu)造函數(shù)的學(xué)習(xí):
1、回憶數(shù)據(jù)類(lèi)型轉(zhuǎn)換:
在平時(shí)寫(xiě)代碼的時(shí)候,最怕的就是那種隱式數(shù)據(jù)類(lèi)型轉(zhuǎn)換了,一不小心,軟件就bug不斷;而顯式數(shù)據(jù)類(lèi)型(一般是程序自己去強(qiáng)制類(lèi)型轉(zhuǎn)換,這個(gè)是我們能夠明顯的識(shí)別和掌控的)。為此我們這里總結(jié)了一副隱式類(lèi)型轉(zhuǎn)換的圖:

下面我們來(lái)幾個(gè)隱式轉(zhuǎn)換的例子:
代碼版本一:
#include?
#include?
int?main()
{
?????short?s?='a';
?????unsigned?int?ui?=?100;
?????int?i?=?-200;
?????double?d?=?i;
?????std::cout<<"d?="?<?????std::cout<<"ui=?"<
?????if((ui+i)>0)
?????{
??????????std::cout<<"Postive"<?????}
?????else
?????{
????????std::cout<<"Negative"<?????}
?????return?0;
}
輸出結(jié)果:
root@txp-virtual-machine:/home/txp#?./a.out
d?=-200
ui=?100
Postive
注解:這里我們明顯發(fā)現(xiàn)(-200+100)還是大于0,這顯然不符合正常人的思維了;所以我們仔細(xì)分析一下,發(fā)現(xiàn)這里肯定是進(jìn)行了隱式轉(zhuǎn)換了,為此我們?cè)偌右粭l語(yǔ)句看看(ui+i)的值到底是多少:
代碼版本二:
#include?
#include?
int?main()
{
?????short?s?='a';
?????unsigned?int?ui?=?100;
?????int?i?=?-200;
?????double?d?=?i;
?????std::cout<<"d?="?<?????std::cout<<"ui=?"<
?????if((ui+i)>0)
?????{
????????std::cout<<"(ui+i)?=?"<????????std::cout<<"Postive"<?????}
?????else
?????{
????????std::cout<<"Negative"<?????}
?????return?0;
}
輸出結(jié)果:
root@txp-virtual-machine:/home/txp#?./a.out
d?=-200
ui=?100
(ui+i)?=?4294967196
Postive
注解:通過(guò)打印(ui+i)的值我們發(fā)現(xiàn),i原本是int數(shù)據(jù)類(lèi)型,這里隱式轉(zhuǎn)換成無(wú)符號(hào)的數(shù)據(jù)類(lèi)型了
為了讓大家更加理解隱式的轉(zhuǎn)換,我們下面再來(lái)一個(gè)例子:
代碼版本三:
#include?
#include?
int?main()
{
?????short?s?='a';
?????unsigned?int?ui?=?100;
?????int?i?=?-200;
?????double?d?=?i;
?????std::cout<<"d?="?<?????std::cout<<"ui=?"<
?????if((ui+i)>0)
?????{
????????std::cout<<"(ui+i)?=?"<????????std::cout<<"Postive"<?????}
?????else
?????{
????????std::cout<<"Negative"<?????}
?????std::cout<<"sizeof(s+'b')?=?"<'b')<
?????return?0;
}
輸出結(jié)果:
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?./a.out
d?=-200
ui=?100
(ui+i)?=?4294967196
Postive
sizeof(s+'b')?=?4
注解:這里我們發(fā)現(xiàn)sizeof出來(lái)的內(nèi)存大小是4個(gè)字節(jié)大小;其實(shí)這里編譯器把short和char類(lèi)型的都轉(zhuǎn)換int類(lèi)型了,所以最終兩個(gè)int數(shù)據(jù)相加,所占的內(nèi)存大小就是int類(lèi)型了。
所以咋們平時(shí)在寫(xiě)代碼的時(shí)候,腦袋里面要有這種寫(xiě)代碼謹(jǐn)慎的思維,防止出現(xiàn)這種隱式轉(zhuǎn)換的情況出現(xiàn),養(yǎng)成寫(xiě)代碼的好習(xí)慣
2、普通類(lèi)型與類(lèi)類(lèi)型之間能否進(jìn)行類(lèi)型轉(zhuǎn)換,類(lèi)類(lèi)型之間又是否能夠類(lèi)型轉(zhuǎn)換呢?
為了說(shuō)明這些問(wèn)題,咋們通過(guò)實(shí)際的代碼測(cè)試來(lái)看看啥情況:
代碼:普通類(lèi)型轉(zhuǎn)換成類(lèi)類(lèi)型
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=6;?從?C?語(yǔ)言角度,這里將?5?強(qiáng)制類(lèi)型轉(zhuǎn)換到?Test?類(lèi)型,只不過(guò)編譯器?在這里做了隱式類(lèi)型轉(zhuǎn)換
?????return?0;
}
輸出結(jié)果(顯示可以編譯通過(guò))
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?./a.out
代碼類(lèi)類(lèi)型轉(zhuǎn)換為普通類(lèi)型
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????int?i?=?t;
?????return?0;
}
輸出結(jié)果(沒(méi)有編譯通過(guò))
root@txp-virtual-machine:/home/txp#?g++?test.cpp
test.cpp:?In?function?‘int?main()’:
test.cpp:21:14:?error:?cannot?convert?‘Test’?to?‘int’?in?initialization
??????int?i?=?t;
??????????????^
代碼類(lèi)類(lèi)型與類(lèi)類(lèi)型之間的轉(zhuǎn)換:
#include?
#include?
class?Value{
};
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????Value?i;
?????t=i;
?????return?0;
}
輸出結(jié)果(暫時(shí)還是不行,編譯不通過(guò)):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
test.cpp:?In?function?‘int?main()’:
test.cpp:27:7:?error:?no?match?for?‘operator=’?(operand?types?are?‘Test’?and?‘Value’)
??????t=i;
???????^
test.cpp:27:7:?note:?candidate?is:
test.cpp:9:7:?note:?Test&?Test::operator=(const?Test&)
?class?Test{
???????^
test.cpp:9:7:?note:???no?known?conversion?for?argument?1?from?‘Value’?to?‘const?Test&’
說(shuō)明:上面的例子,我們只是簡(jiǎn)單的按照實(shí)際角度出發(fā),發(fā)現(xiàn)確實(shí)有寫(xiě)轉(zhuǎn)換行不通。那么真理到底是怎樣的?我們接著往下看
3、轉(zhuǎn)換構(gòu)造函數(shù)出廠:
我們前面學(xué)習(xí)過(guò)構(gòu)造函數(shù),構(gòu)造函數(shù)它可以定義不同類(lèi)型的參數(shù);但是我們今天這里所說(shuō)的轉(zhuǎn)換構(gòu)造函數(shù)的定義時(shí)這樣的:
有且僅有一個(gè)參數(shù)
參數(shù)是基本類(lèi)型
參數(shù)是其它類(lèi)型
接著我們對(duì)上面的普通數(shù)據(jù)類(lèi)型轉(zhuǎn)換類(lèi)類(lèi)型的代碼進(jìn)行分析:
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=6;?//從?C?語(yǔ)言角度,這里將?5?強(qiáng)制類(lèi)型轉(zhuǎn)換到?Test?類(lèi)型,只不過(guò)編譯器?在這里做了隱式類(lèi)型轉(zhuǎn)換
?????return?0;
}
分析:
上面的Test(int i )就是一個(gè)轉(zhuǎn)換構(gòu)造函數(shù),所以我們上面的這句隱式轉(zhuǎn)換語(yǔ)句:
?t?=6
這里其實(shí)發(fā)生了我們剛才說(shuō)的利用了轉(zhuǎn)換構(gòu)造函數(shù),把6轉(zhuǎn)換成Test(6),而這樣寫(xiě)就會(huì)產(chǎn)生一臨時(shí)對(duì)象,所以就可以進(jìn)行賦值了;但是在現(xiàn)在的技術(shù)發(fā)展中,肯定是不希望出現(xiàn)這種要人去防止這隱式轉(zhuǎn)換,所以在c++中有了新技術(shù)來(lái)防止出現(xiàn)隱式轉(zhuǎn)換:
工程中通過(guò)explicit關(guān)鍵字杜絕編譯器的轉(zhuǎn)換嘗試
轉(zhuǎn)換構(gòu)造函數(shù)被explicit修飾只能進(jìn)行顯示轉(zhuǎn)換(也就是強(qiáng)制類(lèi)型轉(zhuǎn)換)
代碼實(shí)踐一:
#include?
#include?
class?Test{
public:
????Test()
????{
????}
???explicit?Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=6;
?????return?0;
}
輸出結(jié)果:
root@txp-virtual-machine:/home/txp#?g++?test.cpp
test.cpp:?In?function?‘int?main()’:
test.cpp:21:8:?error:?no?match?for?‘operator=’?(operand?types?are?‘Test’?and?‘int’)
??????t?=6;
????????^
test.cpp:21:8:?note:?candidate?is:
test.cpp:4:7:?note:?Test&?Test::operator=(const?Test&)
?class?Test{
???????^
test.cpp:4:7:?note:???no?known?conversion?for?argument?1?from?‘int’?to?‘const?Test&’
注解:這里顯示不能這樣轉(zhuǎn)換
代碼實(shí)踐二(進(jìn)行顯示轉(zhuǎn)換):
#include?
#include?
class?Test{
public:
????Test()
????{
????}
???explicit?Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=static_cast(6);
?????return?0;
}
輸出結(jié)果(編譯通過(guò)):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
4、小結(jié):
轉(zhuǎn)換構(gòu)造函數(shù)只有一個(gè)參數(shù)
轉(zhuǎn)換構(gòu)造函數(shù)的參數(shù)類(lèi)型是其它類(lèi)型
轉(zhuǎn)換構(gòu)造函數(shù)在類(lèi)型轉(zhuǎn)換時(shí)被調(diào)用
隱式類(lèi)型轉(zhuǎn)換是工程中bug的重要來(lái)源
explicit關(guān)鍵字用于杜絕隱式類(lèi)型轉(zhuǎn)換
二、類(lèi)型轉(zhuǎn)換函數(shù):
1、類(lèi)類(lèi)型轉(zhuǎn)換普通類(lèi)型:
在我們上面通過(guò)代碼測(cè)試發(fā)現(xiàn)不行,那么是真的不行嗎,事實(shí)是可以進(jìn)行轉(zhuǎn)換的,不過(guò)要用到我們現(xiàn)在c++里面的類(lèi)型轉(zhuǎn)換函數(shù)(它用于將類(lèi)對(duì)象轉(zhuǎn)換為其它類(lèi)型),類(lèi)型轉(zhuǎn)換的語(yǔ)法如下:
operator?Type()
{
????Type?ret;
?????
????return?ret;
}
代碼實(shí)踐:
#include?
#include?
class?Test{
public:
????Test()
????{
????}
???operator?int()
???{
????}
};
int?main()
{
?????Test?t;
?????int?i?=t;
?????return?0;
}
輸出結(jié)果(編譯沒(méi)有報(bào)錯(cuò)):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
注:
與轉(zhuǎn)換構(gòu)造函數(shù)具有同等的地位
使得編譯器有能力將對(duì)象轉(zhuǎn)化為其它類(lèi)型
編譯器能夠隱式的使用類(lèi)型轉(zhuǎn)換函數(shù)
2、類(lèi)類(lèi)型之間的轉(zhuǎn)換:
這個(gè)問(wèn)題也是之前我們上面簡(jiǎn)單的測(cè)試,不能進(jìn)行類(lèi)類(lèi)型之間的轉(zhuǎn)換;現(xiàn)在我們學(xué)習(xí)了類(lèi)型轉(zhuǎn)換函數(shù),是可以進(jìn)行轉(zhuǎn)換的:
代碼版本一:
#include?
#include?
using?namespace?std;
class?Test;
class?Value
{
public:
????Value()
????{
????}
????explicit?Value(Test&?t)
????{
????}
};
class?Test
{
????int?mValue;
public:
????Test(int?i?=?0)
????{
????????mValue?=?i;
????}
????int?value()
????{
????????return?mValue;
????}
????operator?Value()
????{
????????Value?ret;
????????cout?<"operator?Value()"?<????????return?ret;
????}
/*工程上通過(guò)以下方式;
??Value?toValue()
??{
??????Value?ret;
???????
??????return?ret;
??
??}
};
int?main()
{???
????Test?t(100);
????Value?v?=?t;
????
????return?0;
}
輸出結(jié)果(編譯通過(guò)):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
注意:這里還有一種讓編譯器犯難的轉(zhuǎn)換寫(xiě)法;我們上面這樣寫(xiě)是用explicit關(guān)鍵字屏蔽了Value類(lèi)里面的隱式轉(zhuǎn)換,所以不會(huì)犯難,下面是犯難的代碼示例:
#include?
#include?
using?namespace?std;
class?Test;
class?Value
{
public:
????Value()
????{
????}
?????Value(Test&?t)
????{
????}
};
class?Test
{
????int?mValue;
public:
????Test(int?i?=?0)
????{
????????mValue?=?i;
????}
????int?value()
????{
????????return?mValue;
????}
????operator?Value()
????{
????????Value?ret;
????????cout?<"operator?Value()"?<????????return?ret;
????}
};
int?main()
{???
????Test?t(100);
????Value?v?=?t;
????
????return?0;
}
輸出結(jié)果:
root@txp-virtual-machine:/home/txp#?g++?test.cpp
test.cpp:?In?function?‘int?main()’:
test.cpp:42:15:?error:?conversion?from?‘Test’?to?‘Value’?is?ambiguous
?????Value?v?=?t;
???????????????^
test.cpp:41:10:?note:?candidates?are:
?????Test?t(100);
??????????^
test.cpp:31:5:?note:?Test::operator?Value()
?????operator?Value()
?????^
test.cpp:14:6:?note:?Value::Value(Test&)
??????Value(Test&?t)
3、小結(jié):
無(wú)法抑制隱式的類(lèi)型轉(zhuǎn)換函數(shù)調(diào)用
類(lèi)型轉(zhuǎn)換函數(shù)可能與轉(zhuǎn)換構(gòu)造函數(shù)起沖突
當(dāng)然工程中可能比較習(xí)慣用 Type toType()的公有成員代替類(lèi)型轉(zhuǎn)換函數(shù)(就是換了種寫(xiě)法)
