Loki库:类型间耦合检测和去耦合

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

Loki库:类型间耦合检测和去耦合

 

      数据类型之间的联系主要有两类:一,类型之间存在着自动转换关系;二,类型间存在着继承关系,虽然它其实也表明了某种转换(主要是对象切片和指针向上映射)。

      那么,如何判断类型间存在转换或继承呢?LokiTypeManip提供了很精彩很完美的解决方法(注:《More Exceptional C++Item 4也给出了讲解,可以参考。):

 

//WQ注:和以前讨论过的TypeList一样,Conversion类也是供编译期使用

//的,所以靠提供萃取来解决问题的。

    template <class T, class U>

    struct Conversion

    {

        typedef Private::ConversionHelper<T, U> H;

#ifndef __MWERKS__

        //WQ注:这是精妙所在!讲解太长,放到后面进行。

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

#else

        enum { exists = false };

#endif

        enum { exists2Way = exists && Conversion<U, T>::exists };

        enum { sameType = false };

    };

    //WQ注:用偏特化解决相同类型

    template <class T>

    struct Conversion<T, T>   

    {

        enum { exists = 1, exists2Way = 1,sameType = 1 };

    };

    // WQ注:用偏特化和特化解决void

    template <class T>

    struct Conversion<void, T>   

    {

        enum { exists = 1, exists2Way = 0,sameType = 0 };

    };

   

    template <class T>

    struct Conversion<T, void>   

    {

        enum { exists = 1, exists2Way = 0,sameType = 0 };

    };

   

    template <>

    class Conversion<void, void>   

    {

    public:

        enum { exists = 1, exists2Way = 1,sameType = 1 };

    };   

}

 

先看辅助类ConversionHelper的定义:

        template <class T, class U>

        struct ConversionHelper

        {

            typedef char Small;

struct Big { char dummy[2]; };

//WQ注:注意,下面三个函数并没有实现体!

            static Big   Test(...);//WQ注:C++中,不定参数已不需要“至少一个定参”了。

            static Small Test(U);

            static T MakeT();

        };

看其中的Test函数,如果TU之间存在转换关系的话,根据重载决策,肯定调Big Test(U)函数。依靠两个函数的返回类型并不相同,就可以判断出调了那个版本,于是也就推测出TU之间是否存在转换关系了。

回过头来再看前面的使用:sizeof(typename H::Small) == sizeof(H::Test(H::MakeT()));由于我们讲过,Conversion是编译期使用的类,不想采用对返回值采用运行期比较运算,恰好有sizeof()运算满足要求。所以,ConversionHelper将两个Test函数的返回类型实现得在大小上不等。

令人崩溃的事来了:由于我们只使用了BigSmall的大小而没有用它的值,所以,可以根本不用真的创建返回对象,Test函数也不必真的被调用,于是所有行为都是编译期的了。C++说,你可以不用创建并没有被真的使用的东西,所以,Test函数可以不用被定义,只要有这个申明就行了。是的,Loki库中确实没有定义这三个函数!崩溃啊,崩溃!在没搞懂这一点之前,我反复搜索了全部源码,并认为我下载了一个不完全的版本,然后四处搜索最新版本,着实乱了好一阵。虽然我不敢说所有C++编译器都能支持这一点,但我使用的VCBCBDevCPP三个主流编译器都正确支持了这一点,Loki的源码能够正确编译和使用。

     如何判断两个类型间存在继承关系?很简单:派生类指针类型可以自动向上映射为基类指针类型。当然还得排除“同类型指针间”和“非void *void *间”这两种情况。Loki库源码如下:

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

// macro SUPERSUBCLASS

// Invocation: SUPERSUBCLASS(B, D) where B and D are types.

// Returns true if B is a public base of D, or if B and D are aliases of the

// same type.

//

// Caveat: might not work if T and U are in a private inheritance hierarchy.

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

 

#define SUPERSUBCLASS(T, U) /

    (::Loki::Conversion<const U*, const T*>::exists && /

    !::Loki::Conversion<const T*, const void*>::sameType)

 

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

// macro SUPERSUBCLASS_STRICT

// Invocation: SUPERSUBCLASS_STRICT(B, D) where B and D are types.

// Returns true if B is a public base of D.

//

// Caveat: might not work if T and U are in a private inheritance hierarchy.

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

 

#define SUPERSUBCLASS_STRICT(T, U) /

    (SUPERSUBCLASS(T, U) && /

!::Loki::Conversion<const T, const U>::sameType)//WQ注:有人指出此处最好使用const T *,const U *,但确实TU就足够了,只是编译耗时可能要多一点点,反正运行期都是没有任何开销。

      故事还没有结束,提供的萃取值是int01(当然也可以认为等价于boolfalsetrue),它们只能作运行期运算的,那么如何编译期使用这些结果?Loki库同样有精彩的解决方法:

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

// class template Int2Type

// Converts each integral constant into a unique type

// Invocation: Int2Type<v> where v is a compile-time constant integral

// Defines 'value', an enum that evaluates to v

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

 

    template <int v>

    struct Int2Type

    {

        enum { value = v };

};

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

// class template Select

// Selects one of two types based upon a boolean constant

// Invocation: Select<flag, T, U>::Result

// where:

// flag is a compile-time boolean constant

// T and U are types

// Result evaluates to T if flag is true, and to U otherwise.

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

 

    template <bool flag, typename T, typename U>

    struct Select  

    {

        typedef T Result;

    };

    template <typename T, typename U>

    struct Select<false, T, U>

    {

        typedef U Result;

};

    

Select,一个编译期的?:运算。编译期只能靠类型推导(模板),类型判决(重载)来选择不同的分支。Int01自然不在这两种情况之列,但Int2Type<0>Int2Type<1>当然是满足的。依靠偏特化,Select圆满完成了它的任务。

 

      类型之间有自动转换当然是极有用的,但很多时候却也造成麻烦:一,很容易产生转换多径,尤以多继承时最为麻烦;二,发生期望外的转换而得到期望外的行为,尤以重载时的情况最为混乱;三,转换不够精确,不能完全满足需要,问题发生在向下类型映射时。

      在适当的时候去除了类型间耦合就可以避免这三方面副作用。

      类型间去耦合有两种方法:一,用模板封装;二,指向指针的指针。

方法一的实现太简单了:

template<typename T>

struct Type2Type

{

    typedef  T  OriginalType;

}    

      多个T之间的转换和继承关系在Type2Type<T>之间再不存在了。更为神奇的是,向下类型映射将可以精确进行的,但这得结合其具体使用来讲,我把它留到下一篇《多继承的改良》中讲。


 

《Modern C++ Design》源码Loki库读解随感二:类型间耦合检测和去耦合

Loki库读解随感二:类型间耦合检测和去耦合过了如许之久才有这随感二,实在不好意思。原因是我虽然读懂了Loki的每一行代码,却实在未能理解如何去使用这些代码,直到近来才渐渐有所悟的。       数据...
  • taodm
  • taodm
  • 2002年10月20日 09:21
  • 1653

软件工程中的各种耦合类型

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决与模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用...
  • qq_20480611
  • qq_20480611
  • 2016年05月06日 10:43
  • 3767

软件工程中的耦合类型

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决与模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用...
  • Scythe666
  • Scythe666
  • 2017年03月24日 21:17
  • 783

模块之间的耦合问题

简介 一般模块之间可能的连接方式有七种,构成耦合性的七种类型。它们之间的关系为(独立性由强到弱) 非直接耦合(Nondirect Coupling) 如果两个模块之间没有直接...
  • bigtree_3721
  • bigtree_3721
  • 2015年12月17日 21:30
  • 1563

内聚耦合分类

耦合可以分为以下几种,它们之间的耦合度由高到低排列如下: (1) 内容耦合:一个模块直接访问另一模块的内容,则称这两个模块为内容耦合。 若在程序中出现下列情况之一,则说明两个模块之间发生了...
  • learner811
  • learner811
  • 2017年03月06日 21:46
  • 1203

软件工程中的五种耦合

数据耦合 sum(int a,int b) {int c; c=a+b; return(c); } main() {int x,y; . . .printf("x+y=%d",sum(x,y)); }...
  • c30gcrk
  • c30gcrk
  • 2007年12月17日 11:20
  • 528

如何降低代码的耦合

降低代码的耦合,通常需要暴露一个接口,提供一个回调函数。 例如短信备份时,短信备份的代码(序列化短信到xml文件,保存为xml是因为xml具有跨平台的好处,android备份的短信也可以在ios系统...
  • XiaoShuaZi
  • XiaoShuaZi
  • 2015年05月02日 22:05
  • 1609

软件工程-耦合内聚

耦合性也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。 模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。...
  • suniyadadechuentian
  • suniyadadechuentian
  • 2015年06月01日 15:33
  • 1428

耦合与耦合性区别(二)

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决与模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用...
  • u012999868
  • u012999868
  • 2015年06月30日 16:13
  • 557

服务化了,没想到耦合更加严重?

通过“库”来实现业务,可能会引发业务系统之间耦合,需要通用业务服务化,将通用业务下沉,详见《小小的公共库,大大的耦合,你痛过吗》。 通过“join”来实现业务,可能会导致数据库之间耦合,需要...
  • z50L2O08e2u4afToR9A
  • z50L2O08e2u4afToR9A
  • 2017年12月05日 00:00
  • 77
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Loki库:类型间耦合检测和去耦合
举报原因:
原因补充:

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