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

下面我們來幾個隱式轉(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,這顯然不符合正常人的思維了;所以我們仔細分析一下,發(fā)現(xiàn)這里肯定是進行了隱式轉(zhuǎn)換了,為此我們再加一條語句看看(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
注解:通過打印(ui+i)的值我們發(fā)現(xiàn),i原本是int數(shù)據(jù)類型,這里隱式轉(zhuǎn)換成無符號的數(shù)據(jù)類型了
為了讓大家更加理解隱式的轉(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<<"(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出來的內(nèi)存大小是4個字節(jié)大?。黄鋵嵾@里編譯器把short和char類型的都轉(zhuǎn)換int類型了,所以最終兩個int數(shù)據(jù)相加,所占的內(nèi)存大小就是int類型了。
所以咋們平時在寫代碼的時候,腦袋里面要有這種寫代碼謹慎的思維,防止出現(xiàn)這種隱式轉(zhuǎn)換的情況出現(xiàn),養(yǎng)成寫代碼的好習(xí)慣
2、普通類型與類類型之間能否進行類型轉(zhuǎn)換,類類型之間又是否能夠類型轉(zhuǎn)換呢?
為了說明這些問題,咋們通過實際的代碼測試來看看啥情況:
代碼:普通類型轉(zhuǎn)換成類類型
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=6;?從?C?語言角度,這里將?5?強制類型轉(zhuǎn)換到?Test?類型,只不過編譯器?在這里做了隱式類型轉(zhuǎn)換
?????return?0;
}
輸出結(jié)果(顯示可以編譯通過)
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?./a.out
代碼類類型轉(zhuǎn)換為普通類型
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????int?i?=?t;
?????return?0;
}
輸出結(jié)果(沒有編譯通過)
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;
??????????????^
代碼類類型與類類型之間的轉(zhuǎn)換:
#include?
#include?
class?Value{
};
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????Value?i;
?????t=i;
?????return?0;
}
輸出結(jié)果(暫時還是不行,編譯不通過):
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&’
說明:上面的例子,我們只是簡單的按照實際角度出發(fā),發(fā)現(xiàn)確實有寫轉(zhuǎn)換行不通。那么真理到底是怎樣的?我們接著往下看
3、轉(zhuǎn)換構(gòu)造函數(shù)出廠:
我們前面學(xué)習(xí)過構(gòu)造函數(shù),構(gòu)造函數(shù)它可以定義不同類型的參數(shù);但是我們今天這里所說的轉(zhuǎn)換構(gòu)造函數(shù)的定義時這樣的:
有且僅有一個參數(shù)
參數(shù)是基本類型
參數(shù)是其它類型
接著我們對上面的普通數(shù)據(jù)類型轉(zhuǎn)換類類型的代碼進行分析:
#include?
#include?
class?Test{
public:
????Test()
????{
????}
????Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=6;?//從?C?語言角度,這里將?5?強制類型轉(zhuǎn)換到?Test?類型,只不過編譯器?在這里做了隱式類型轉(zhuǎn)換
?????return?0;
}
分析:
上面的Test(int i )就是一個轉(zhuǎn)換構(gòu)造函數(shù),所以我們上面的這句隱式轉(zhuǎn)換語句:
?t?=6
這里其實發(fā)生了我們剛才說的利用了轉(zhuǎn)換構(gòu)造函數(shù),把6轉(zhuǎn)換成Test(6),而這樣寫就會產(chǎn)生一臨時對象,所以就可以進行賦值了;但是在現(xiàn)在的技術(shù)發(fā)展中,肯定是不希望出現(xiàn)這種要人去防止這隱式轉(zhuǎn)換,所以在c++中有了新技術(shù)來防止出現(xiàn)隱式轉(zhuǎn)換:
工程中通過explicit關(guān)鍵字杜絕編譯器的轉(zhuǎn)換嘗試
轉(zhuǎn)換構(gòu)造函數(shù)被explicit修飾只能進行顯示轉(zhuǎn)換(也就是強制類型轉(zhuǎn)換)
代碼實踐一:
#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)換
代碼實踐二(進行顯示轉(zhuǎn)換):
#include?
#include?
class?Test{
public:
????Test()
????{
????}
???explicit?Test(int?i)
????{
????}
};
int?main()
{
?????Test?t;
?????t?=static_cast(6);
?????return?0;
}
輸出結(jié)果(編譯通過):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
4、小結(jié):
轉(zhuǎn)換構(gòu)造函數(shù)只有一個參數(shù)
轉(zhuǎn)換構(gòu)造函數(shù)的參數(shù)類型是其它類型
轉(zhuǎn)換構(gòu)造函數(shù)在類型轉(zhuǎn)換時被調(diào)用
隱式類型轉(zhuǎn)換是工程中bug的重要來源
explicit關(guān)鍵字用于杜絕隱式類型轉(zhuǎn)換
二、類型轉(zhuǎn)換函數(shù):
1、類類型轉(zhuǎn)換普通類型:
在我們上面通過代碼測試發(fā)現(xiàn)不行,那么是真的不行嗎,事實是可以進行轉(zhuǎn)換的,不過要用到我們現(xiàn)在c++里面的類型轉(zhuǎn)換函數(shù)(它用于將類對象轉(zhuǎn)換為其它類型),類型轉(zhuǎn)換的語法如下:
operator?Type()
{
????Type?ret;
?????
????return?ret;
}
代碼實踐:
#include?
#include?
class?Test{
public:
????Test()
????{
????}
???operator?int()
???{
????}
};
int?main()
{
?????Test?t;
?????int?i?=t;
?????return?0;
}
輸出結(jié)果(編譯沒有報錯):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
注:
與轉(zhuǎn)換構(gòu)造函數(shù)具有同等的地位
使得編譯器有能力將對象轉(zhuǎn)化為其它類型
編譯器能夠隱式的使用類型轉(zhuǎn)換函數(shù)
2、類類型之間的轉(zhuǎn)換:
這個問題也是之前我們上面簡單的測試,不能進行類類型之間的轉(zhuǎn)換;現(xiàn)在我們學(xué)習(xí)了類型轉(zhuǎn)換函數(shù),是可以進行轉(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;
????}
/*工程上通過以下方式;
??Value?toValue()
??{
??????Value?ret;
???????
??????return?ret;
??
??}
};
int?main()
{???
????Test?t(100);
????Value?v?=?t;
????
????return?0;
}
輸出結(jié)果(編譯通過):
root@txp-virtual-machine:/home/txp#?g++?test.cpp
root@txp-virtual-machine:/home/txp#?
注意:這里還有一種讓編譯器犯難的轉(zhuǎn)換寫法;我們上面這樣寫是用explicit關(guān)鍵字屏蔽了Value類里面的隱式轉(zhuǎn)換,所以不會犯難,下面是犯難的代碼示例:
#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é):
無法抑制隱式的類型轉(zhuǎn)換函數(shù)調(diào)用
類型轉(zhuǎn)換函數(shù)可能與轉(zhuǎn)換構(gòu)造函數(shù)起沖突
當然工程中可能比較習(xí)慣用 Type toType()的公有成員代替類型轉(zhuǎn)換函數(shù)(就是換了種寫法)
