Chinaunix首页 | 论坛 | 博客
  • 博客访问: 747671
  • 博文数量: 239
  • 博客积分: 60
  • 博客等级: 民兵
  • 技术积分: 1045
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-22 18:25
文章分类

全部博文(239)

文章存档

2019年(9)

2018年(64)

2017年(2)

2016年(26)

2015年(30)

2014年(41)

2013年(65)

2012年(2)

分类: C/C++

2013-02-18 14:57:39

    在 C++ 中“侦测转换能力”的想法是:合并运用sizeof和重载函数面对两个陌生的类型T和U, 我们想在编译期间发掘U是否继承自T,意味着不必使用dynamic_cast耗损执行期效率, 发掘这种继承关系, 靠的是用来侦没可转换性机制和威力惊人的sizeof操作符. sizeof用在任何表达式,可以感知重载、模板具现、转换规则以及任何可以发生在C++表达式身上的机制,并且会直接传回大小,不需拖到执行期评估。(内容源自书籍 mordern C++ design:generic programming and design patterns applied)。我们使用如下测试代码。 (如果存在继承关系,T代表base, U代码super) 

#include 
#include 

template 
class Conversion {
	typedef char Small;
	class Big{char dummy[16];};

	static Small Test(U);
	static Big Test(...);
	static T MakeT();

public:
	enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
	enum { exists2Way = (exists && Conversion::exists) };
	enum { sameType = false};
};

template 
class Conversion
{
public:
	enum { exists = 1, exists2Way = 1, sameType = 1};
};

class Base
{
	char * member;
};

class Super : public Base
{
	char * superMember;
};

#define SUPERSUBCLASS(BASE, SUPER)         ( (Conversion::exists ) && !(Conversion::sameType ) )
#define SUPERSUBCLASS_STRICT(BASE, SUPER)  ( SUPERSUBCLASS(BASE, SUPER) && !(Conversion::sameType) )

int main(int argc, char* argv[])
{
	using namespace std;
	cout<::exists<<"\t"
		<::exists<<"\t"
		< >::exists<<"\t"
		<) "<)<<"\n"
		<) "<)<<"\n"
		<
输出的结果为:
1	0	0	
SUPERSUBCLASS(double, int) 0
SUPERSUBCLASS(Base, Super) 1
SUPERSUBCLASS(Super, Base) 0
SUPERSUBCLASS(char, char*) 0
SUPERSUBCLASS(char *, void*) 0
SUPERSUBCLASS(void *, void*) 1
SUPERSUBCLASS(size_t, vector) 0

SUPERSUBCLASS_STRICT(double, int) 0
SUPERSUBCLASS_STRICT(Base, Super) 1
SUPERSUBCLASS_STRICT(Super, Base) 0
SUPERSUBCLASS_STRICT(char, char*) 0
SUPERSUBCLASS_STRICT(char *, void*) 0
SUPERSUBCLASS_STRICT(void *, void*) 0
SUPERSUBCLASS_STRICT(size_t, vector) 0

根据示例,我们需要分析编译期间侦测可转换性和继承性两个方面。

(一)首先进行编译期间可转换性的分析。

    (1)我们提供两个重载函数

        Small  Test(U); //该重载函数接受转换目标的U类型

        Big  Test(...);  //接受任何其他类型

我们以类型T的临时对象来调用这些重载函数,如果接受U的那个函数"Small  Test(U)"被调用,我们就知道类型T可以转换为U类型;否则如果调用"Big Test(..)"则T类型就无法转换成U类型。为知道哪个重载函数被调用,我们对重载函数的返回值安排了不同的大小和类型,并用sizeof来区分大小。其中,类型本身无关紧要,重要的是它们的大小必须保证不同,我们使用的Small和Big肯定满足这个要求。在C++中,调用本示例的重载函数"Big Test(...)"的结果会如何并不能知道,但是我们此处不真正调用这个重载函数,它甚至没有被实例化,因为sizeof并不对它求值。

    我们传一个T对象给Test(), 并使用sizeof在函数的返回值, 代码可以写成const  bool  convExists= ( sizeof(Test(T())) == sizeof(Small) );由于类型T可能将自己的默认构造函数设为private, 此时T()会编译失败,由于sizeof不会对任何表达式求值,此处我们使用的解决方法是strawman function方法返回一个T类型对象,即实现如下代码

            T  MakeT();

             enum  { exists = sizeof(Test(MakeT())) == sizeof(Small)};

    此处需要注意的是,像MakeT()和Test()不只没做任何事情,甚至根本没有被实例化,根本不真正存在。

    (2)在类型T和类型U之间可能存在双向转换或者相同类型。示例中我们使用exists2Way 表示类型T和类型U之间是否可以双向转换,如果exists2Way = true表示可以双向转换;使用sameType表示类型T和类型U是否相同类型,如果sameType = true表示是相同类型。在如下代码部分是我们的功能代码

template 
class Conversion
{
        ...	
	enum { exists2Way = (exists && Conversion::exists) };
	enum { sameType = false};
};
。我们同时需要使用模板partial  spacialization显示实例化Conversion来实现sameType = true的相同类型版本,如下功能代码
template 
class Conversion
{
public:
	enum { exists = 1, exists2Way = 1, sameType = 1};
};
。类型相同肯定存在双向转换,这样我们就成功实现功能代码。


    (3)编译期间可转换性的输出结果的分析,相关的输出结果是:1   0    0 ; 这个结果是由代码

int main(int argc, char* argv[])
{
	using namespace std;
	cout<::exists<<"\t"
		<::exists<<"\t"
		< >::exists<<"\t"
		<
			

输出的。结果很显然。特别需要注意的是,在输出结果中,代码"< >"输出的是0,因为vector的构造函数是explicit,explicit构造函数是无法担任转换函数的。

 (二)类型的继承性分析。在C++中,子类的指针可以安全的转换到基类指针, 示例中使用代码

...
#define SUPERSUBCLASS(BASE, SUPER)         ( (Conversion::exists ) && !(Conversion::sameType ) )
#define SUPERSUBCLASS_STRICT(BASE, SUPER)  ( SUPERSUBCLASS(BASE, SUPER) && !(Conversion::sameType) )

...

	cout<<"SUPERSUBCLASS(double, int) "<) "<)<<"\n"
		<) "<)<<"\n"
		<
			

实现两个类型的继承判断,输出结果为:

SUPERSUBCLASS(double, int) 0
SUPERSUBCLASS(Base, Super) 1
SUPERSUBCLASS(Super, Base) 0
SUPERSUBCLASS(char, char*) 0
SUPERSUBCLASS(char *, void*) 0
SUPERSUBCLASS(void *, void*) 1
SUPERSUBCLASS(size_t, vector) 0

SUPERSUBCLASS_STRICT(double, int) 0
SUPERSUBCLASS_STRICT(Base, Super) 1
SUPERSUBCLASS_STRICT(Super, Base) 0
SUPERSUBCLASS_STRICT(char, char*) 0
SUPERSUBCLASS_STRICT(char *, void*) 0
SUPERSUBCLASS_STRICT(void *, void*) 0
SUPERSUBCLASS_STRICT(size_t, vector) 0

根据结果可以知道,版本SUPERSUBCLASS(BASE, SUPER)在类型U是public继承自类型T,或者类型T和类型U是同一类型时,返回true.当SUPERSUBCLASS(BASE, SUPER)对const U*和const T*做"可转换性"评估时, 只有如下三种情况const U*可以隐式转换成const T*:

        1.  T和U是同一类型。

        2.  T是U的一个unambiguous(非歧义的)  public  base.

        3.  T是void

版本SUPERSUBCLASS_STRICT(BASE, SUPER)能够更好的区别出继承关系。其中我们在代码前都加上const 是因为template代码实施const两次,第二个会被忽略,这样就不会因为const而导致转型失败。

    在使用以上判定继承性的时候,我们只能判定以public方式继承的子类,这是一个比较遗憾的缺陷。同时声明了explicit 默认构造函数的类型,也会对断定方法造成很大的影响,因为protected 或者private的默认构造函数,可能会造成sizeof操作符 can not access member或者inaccessible.

阅读(1003) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~