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

类别:VC语言 点击:0 评论:0 推荐:

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