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); }
本文地址:http://com.8s8s.com/it/it2226.htm