Loki库:多继承的改良

转载 2005年05月07日 12:28:00
 

 

Loki库:多继承的改良

 

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

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

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

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

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

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

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实体类从BaseVisitorVisiotr<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实现必然是一传RTTIif判断。现在,由于使用的是

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

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

{    //WQ注:C++中,forifwhile()中都可申明变量的,

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

                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

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

Loki库读解三:多继承的改良多继承,总是被我和goto联系在一起。从逻辑上,它们都是语言的必须组成部分,但在理论上被证明可以完全不使用它们。已经形式了这样的“圣条”:尽可能不要使用它们。并且甚至已被...
  • taodm
  • taodm
  • 2002年10月23日 09:31
  • 2084

Loki库使用介绍

[-] C设计模式类库 Loki介绍与用法 编译 Singleton模式单件模式 头文件类型定义示例代码 对象工厂 Object Factory 头文件类型成员方法示例代码 Abstract ...
  • zhu2695
  • zhu2695
  • 2016年04月25日 22:05
  • 1154

Loki库使用(1)

Loki库使用(1) 2012-11-07 16:44 7090人阅读 评论(2) 收藏 举报 目录(?)[+] C++设计模式类库 Loki介绍与用法 Loki是由Andrei编写的一个与《...
  • zdy0_2004
  • zdy0_2004
  • 2014年10月20日 21:31
  • 1361

《Modern C++ Design》Loki库源码读解随想

《Modern C++ Design》Loki库源码读解随想大牛Andrei Alexandrescu的《Modern C++ Design》讨论的是C++语言的最前沿研究:generative pr...
  • taodm
  • taodm
  • 2002年07月23日 10:52
  • 7379

C++三大库boost、loki、stlport

转: STL是一个标准,各商家根据这个标准开发了各自的STL版本。而在这形形色色的STL版本中,SGI STL无疑是最引人瞩目的一个。这当然是因为这个STL产品系出名门,其设计和编写者名单中,Ale...
  • zww0815
  • zww0815
  • 2016年04月28日 16:14
  • 1938

关于模板偏特化,模板递归,及Loki之Typelist和一些感悟

一直以来,在大多数情况下,递归被看做是低效率的表现,从学习编程开始,就一直被教导,不用或至少少用递归。但在模板编程中,递归和模板偏特化联合,起了相当大的作用。可以说,没有递归,在很大程度上,模板编程便...
  • kewing
  • kewing
  • 2010年10月23日 11:39
  • 2622

【设计模式】--C++设计模式类库 Loki介绍与用法

http://www.usidcbbs.com/simple/?t2428.html http://book.douban.com/subject/1119904/ C++设计模式类库 Lok...
  • Witch_Soya
  • Witch_Soya
  • 2012年05月29日 14:11
  • 3304

Loki库读解-扩展TypeList:Typelist生成器、MaxSizeOf

Loki中的TYPELIST_**宏还是太难用了,因为无法支持不定参数。借鉴于BOOST中的Tuple的想法,实现了这个Typelist_Maker:template         class T6...
  • taodm
  • taodm
  • 2004年04月08日 18:51
  • 1680

阅胡适《文学改良刍议》有感

1 胡适其人 大多数中国人只知道鲁迅,因为我们从小学到中学的课本中都只出现过鲁迅的文章,而没有胡适的文章。人们都只知道《阿Q正传》《狂人日记》《从百草园到三味书屋》,却不知在五四新文化运动中还有《文学...
  • xiahouzuoxin
  • xiahouzuoxin
  • 2014年01月01日 14:19
  • 6152

LOKI库

递归之美 - Loki库TypeList源码剖析 转载于 http://blog.sina.com.cn/s/blog_45497dfa0100ppbp.htmlLOKI库读解:AbstractF...
  • xcw_1987
  • xcw_1987
  • 2016年12月22日 17:39
  • 81
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Loki库:多继承的改良
举报原因:
原因补充:

(最多只允许输入30个字)