你可以使用dynamic_cast,但这会影响运行阶段效率,而这个问题可以在编译阶段处理。这就是它的意义。
sizeof 是在编译阶段就可以搞定一切的操作符,它强大的威力在于它测侦测,举个例子来说:
sizeof (fun());
这是对int求sizeof,尽管你并未定义fun()。
侦测转换能力的想法是运用sizeof和重载。我们定义这样的重载:
Small Test(...);
sizeof (Test(TNAME())) == sizeof (BIG);
如你所见,这太棒了,传入可以转化为U的类型的时候,检测通过,否则失败,正是你想要的结果。
这里有个小问题,如果TNAME的构造函数不可访问怎么办,其实,正如上边所说,sizeof不计较实际是否有代码,它对表达式的判断采取“只看结果”的方式,于是我们可以这样改良这个测试策略
class Conversion
... {
typedef char Small;
static class Big ...{char dummy[2];};
static Small Test(U);
static Big Test(...);
static T MakeT(); //稻草人方法
public:
enum ...{exist = (sizeof(Test(MakeT())) == sizeof(Small))};
} ;
注意使用sizeof特点构造的稻草人函数技巧。
注意,我们是在测试可否转换,但其实负责转换的还是编译器,即使是在我们的测试策略里,也是使用了让编译器负责的方法。这也就是说int和double是可以互相转换的。于是我们可以添加一个互相转换标志:
class Conversion
... {
typedef char Small;
static class Big ...{char dummy[2];};
static Small Test(U);
static Big Test(...);
static T MakeT(); //稻草人方法
public:
enum ...{exist = (sizeof(Test(MakeT())) == sizeof(Small))};
//注意这行
enum ...{exist2Way = exists && Conversion<U,T>::exists};
} ;
对于非常调皮的使用者,他一定会跟你开这样的玩笑Conversion<int,int>::exists,为了对付这种情况,我们使用篇特化:
class Conversion
... {
typedef char Small;
static class Big ...{char dummy[2];};
static Small Test(U);
static Big Test(...);
static T MakeT(); //稻草人方法
public:
enum ...{exist = (sizeof(Test(MakeT())) == sizeof(Small))};
enum ...{exist2Way = exists && Conversion<U,T>::exists};
//注意这行
enum ...{sameType = false};
} ;
template < class T >
class Conversion < T,T >
... {
public:
enum ...{exist = 1,exist2Way = 1,sameType = 1};
} ;
子类指针是可以任意向父类转换的,所以,我们如此判断class是否有继承关系:
如果U继承于T,那么U*可以向T*转换,而且T*和不能是void。关于第二点保证,是避免void*可以转换成目标指针的情况。
可以看出,这个判断里强调了const,这是怕无法通过对const型的测试,但是如果参数本身已经是const呢?
如果template代码实施const两次(对一个已经是const的类型而言),第二个cosnt会被忽略。Andrei如是说。
在loki里你可以使用<TypeManip.h>::SuperSubClass类。