2.7
編譯期間偵測(cè)可轉(zhuǎn)換性和繼承性
在泛型編程中,經(jīng)常遭遇一個(gè)問(wèn)題:對(duì)于兩個(gè)型別T和U,如何得知U是否繼承于T。我們需要在編譯時(shí)發(fā)現(xiàn)這樣的關(guān)系,而不必使用dynamic_cast——它會(huì)損耗執(zhí)行期效率。
我們利用sizeof
和 重載函數(shù)。比如如下定義兩個(gè)類型,和兩個(gè)函數(shù),一個(gè)函數(shù)接收U類型,一個(gè)接收任意類型。
1 typedef char Small;
2 class Big {char dummy[2];};
3 Small Test(U);
4 Big Test(
);//省略號(hào)參數(shù)函數(shù)
我們傳一個(gè)T類型對(duì)象給Test函數(shù),看它能不能轉(zhuǎn)換為U:
1 const bool convExists = sizeof(Test(T())) == sizeof(Small);
但如果T的缺省構(gòu)造函數(shù)為私有,則會(huì)編譯失敗,所以我們用一個(gè)“稻草人函數(shù)”:
1 T MakeT();
2 const bool convExists = sizeof(Test(MakeT())) == sizeof(Small);
我們注意,sizeof()里面的東西不需要具現(xiàn),所以T對(duì)象,MakeT()、Test()都不需要實(shí)作。它們根本不真正存在!!現(xiàn)在用class
template包裝起來(lái)。
1 template<class T, class U>
2 class Conversion
3 {
4 typedef char Small;
5 class Big {char dummy[2];};
6 static Small Test(U);
7 static Big Test(
);
8 static T MakeT();
9 public:
10 // T可以轉(zhuǎn)換為U
11 enum {exists = sizeof(Test(MakeT())) == sizeof(Small)};
12 // 可以雙向轉(zhuǎn)換
13 enum {exists2Way = exists && conversion<U, T>::exists };
14 enum {sameType = false};
15 };
16 //利用偏特化處理 sameType == true 情況
17 template<class T>
18 class Conversion<T, T>
19 {
20 public:
21 enum { exists = 1, exists2Way = 1, sameType = 1};
22 };
最后,我們可以根據(jù)這個(gè)來(lái)判斷兩個(gè)類之間是否有繼承關(guān)系:
1 #define SUPER_SUB_CLASS(T, U)\
2 (Conversion<const U*, const T*>::exists &&\
3 !Conversion<const T*, const void*>::sameType)
如果U是共有繼承于T,或者T和U是同一型別,SUPER_SUB_CLASS(T,
U)都傳回true。這里加上const飾詞的原因是,我們不希望因const而導(dǎo)致轉(zhuǎn)換失敗,對(duì)一個(gè)型別const兩次,第二個(gè)const會(huì)被忽略。