分享
 
 
 

《Modern C++ Design》Loki库读解三:多继承的改良

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Loki库读解三:多继承的改良

多继承,总是被我和goto联系在一起。从逻辑上,它们都是语言的必须组成部分,但在理论上被证明可以完全不使用它们。已经形式了这样的“圣条”:尽可能不要使用它们。并且甚至已被曲解为“绝对不要使用它们”。

在Steve Maguire的《开发过程调试技术》中指出了可以安全使用goto的地方。而在Loki库中也指出了多继承的安全使用。

几乎只有C++支持多重继承,不是多余,而是因为没有支持“interface”。OO中讲应该对接口进行编程,而C++作为严格的编译期类型检查语言,将它曲解为“对类型进行编程”了。于是需要依靠多继承和模板来补救这种缺陷。

多继承会发生问题主要是“菱形缺陷”,以及“this指针的值跳变”。

“this指针的值跳变”主要对“对象同一性”判断制造了障眼法。可参看《Exceptional C++》Item 38,C++只规定相同地址指向的一定是同一对象,而地址不同的并不说明任何问题,所以,使用地址进行“同一性”判断本来就是错误行为(只是绝大部分情况下是可用的),多继承不该对此承担骂名。

用“虚基类”来解决“菱形缺陷”则是使问题更加复杂化了。首先应该还“继承”以本来面目:继承不是为了得到实现,而是为了得到接口。所以,《More Effective C++》Item 33讲,“将非尾端类设计为抽象类”。但这些非尾端的抽象类一般来说是准实体类。要想安全地使用多继承,只能有最多一个基类是准实体类,其它基类必须是纯接口类。这些纯接口类,在《Modern C++ Design》中被限定为主要扮演“策略类”的角色,并叫之为“基于策略编程”。关于“基于策略编程”,由于可以下载到原书1、7两章,及《极限编程研究》上还有一篇论文,所以我就不多谈了。

Loki库中的多继承是依靠TypeList,用二重继承递归实现的,在下面的visitor源码中会看得很清楚。第一反应就是:非常象设计模式中的“外观模式”。实际使用上来说,当然差很远的。我对其使用卡壳了很久,直到现在为止,仍然不能贯通起来,看来只能等书出来了再研究了。想来大家都会对这种用法比较震惊,所有我将在下一篇贴出的HierarchyGenerators.h的源码注解,以供大家集思广益了。

以随感一中讲的visitor模式源码为例,讲解随感二中留下的“精确向下类型映射”:

////////////////////////////////////////////////////////////////////////////////

// class template BaseVisitor

// The base class of any Acyclic Visitor

////////////////////////////////////////////////////////////////////////////////

class BaseVisitor

{

public:

virtual ~BaseVisitor() {} //WQ注:没有visit方法,所有隔绝循环依赖。

};

////////////////////////////////////////////////////////////////////////////////

// class template Visitor

// The building block of Acyclic Visitor

////////////////////////////////////////////////////////////////////////////////

template <class T, typename R = void>

class Visitor

{

public:

typedef R ReturnType;

virtual ReturnType Visit(T&) = 0; //WQ注:这个函数看似不起眼,却很关键

//如果画出继承图,并将它放进去的话,就

//看得很清楚了。

};

////////////////////////////////////////////////////////////////////////////////

// class template Visitor (specialization)

// This specialization is not present in the book. It makes it easier to define

// Visitors for multiple types in a shot by using a typelist. Example:

// //WQ注:这是典型运用,请多体会。

// class SomeVisitor :

// public BaseVisitor // required

// public Visitor<TYPELIST_2(RasterBitmap, Paragraph)>,

// public Visitor<Paragraph>

// {

// public:

// void Visit(RasterBitmap&); // visit a RasterBitmap

// void Visit(Paragraph &); // visit a Paragraph

// };

////////////////////////////////////////////////////////////////////////////////

//WQ注:是前面visitor的偏特化。它自己可独立形成循环依赖的visitor模式。

template <class Head, class Tail, typename R>

class Visitor<Typelist<Head, Tail>, R>

: public Visitor<Head, R>, public Visitor<Tail, R>

{ //WQ注,本想画出递归继承图的,vision图太麻烦了,请自己画吧。

public:

typedef R ReturnType;

// using Visitor<Head, R>::Visit; //WQ注:无需using,因为所有的visit方法都

// using Visitor<Tail, R>::Visit; //都是纯虚函数,必然要在最终类真正实现的

};

//WQ这是递归的结束点。

template <class Head, typename R>

class Visitor<Typelist<Head, NullType>, R> : public Visitor<Head, R>

{

public:

typedef R ReturnType;

using Visitor<Head, R>::Visit;

};

////////////////////////////////////////////////////////////////////////////////

// class template BaseVisitorImpl

// Implements non-strict visitation (you can implement only part of the Visit

// functions)

////////////////////////////////////////////////////////////////////////////////

//WQ注:这是另外一种带默认实现的visitor版本。

template <class TList, typename R = void> class BaseVisitorImpl;

template <class Head, class Tail, typename R>

class BaseVisitorImpl<Typelist<Head, Tail>, R>

: public Visitor<Head, R>

, public BaseVisitorImpl<Tail, R>

{ //WQ注,本想画出递归继承图的,vision图太麻烦了,请自己画吧。

public:

// using BaseVisitorImpl<Tail, R>::Visit;

virtual R Visit(Head&) //WQ注:是对visitor<Head,R>的visit方法的override

{ return R(); } //WQ注:R()对void都成立!

};

template <class Head, typename R>

class BaseVisitorImpl<Typelist<Head, NullType>, R>

: public Visitor<Head, R>

{

public:

virtual R Visit(Head&)

{ return R(); }

};

//WQ注:如前典型用法所示,最终的visitor实体类从BaseVisitor和Visiotr<TypeList>二//重继承。如果TypeList中的多个类型间有继承关系,由于其实际基类是Visitor<T>,继承//关系被隔绝,不存在“菱形缺陷”。

////////////////////////////////////////////////////////////////////////////////

// class template BaseVisitable

////////////////////////////////////////////////////////////////////////////////

template <typename R, typename Visited>

struct DefaultCatchAll

{

static R OnUnknownVisitor(Visited&, BaseVisitor&)

{ return R(); }

};

////////////////////////////////////////////////////////////////////////////////

// class template BaseVisitable

////////////////////////////////////////////////////////////////////////////////

template

<

typename R = void,

template <typename, class> class CatchAll = DefaultCatchAll

>

class BaseVisitable

{

public:

typedef R ReturnType;

virtual ~BaseVisitable() {}

virtual ReturnType Accept(BaseVisitor&) = 0;

protected: // give access only to the hierarchy

template <class T>

static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)

{

//WQ注:这就是所谓的“精确向下类型映射”

//传统Visitor实现下,下面语句为:if (T* p = dynamic_cast<T*>(&guest))

//如果多个Host类间有继承关系,T及其派生类都能使判断成立,转换是不精确的。

//而现在,只有精确的T类型才能成立了。

// Apply the Acyclic Visitor

//WQ注:传统Visitor实现必然是一传RTTI加if判断。现在,由于使用的是

//模板的自动类型推导,不需要对类型进行硬编码,所以,循环依赖被割断!

if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest))

{ //WQ注:C++中,for、if、while的()中都可申明变量的,

//并且生存期只到本语句结束,本例即到下行“}”处。

return p->Visit(visited);

}

return CatchAll<R, T>::OnUnknownVisitor(visited, guest);

}

};

////////////////////////////////////////////////////////////////////////////////

// macro DEFINE_VISITABLE

// Put it in every class that you want to make visitable (in addition to

// deriving it from BaseVisitable<R>

////////////////////////////////////////////////////////////////////////////////

#define DEFINE_VISITABLE()

virtual ReturnType Accept(BaseVisitor& guest)

{ return AcceptImpl(*this, guest); }

////////////////////////////////////////////////////////////////////////////////

// class template CyclicVisitor

// Put it in every class that you want to make visitable (in addition to

// deriving it from BaseVisitable<R>

////////////////////////////////////////////////////////////////////////////////

template <typename R, class TList>

class CyclicVisitor : public Visitor<TList, R>

{

public:

typedef R ReturnType;

// using Visitor<TList, R>::Visit;

template <class Visited>

ReturnType GenericVisit(Visited& host)

{

Visitor<Visited, ReturnType>& subObj = *this;

return subObj.Visit(host);

}

};

////////////////////////////////////////////////////////////////////////////////

// macro DEFINE_CYCLIC_VISITABLE

// Put it in every class that you want to make visitable by a cyclic visitor

////////////////////////////////////////////////////////////////////////////////

#define DEFINE_CYCLIC_VISITABLE(SomeVisitor)

virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest)

{ return guest.GenericVisit(*this); }

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有