• 在编译时决定类型的可继承性


    在编译时决定类型的可继承性

    Posted on 2006-05-15 17:20 nacci 阅读(478) 评论(0)  编辑 收藏 引用 所属分类: C++漫谈

    一段C++的读书笔记

    给定任意2个类型UT,你如何来确定U是否继承于T呢?在编译时发现两个类型的这种关系对于泛型库的优化是极为重要的。在泛型函数中,如果某个类实现了特定的接口,你可以根据这种关系为其利用特定的优化算法。另外,如果我们可以在编译期决定2个类的关系,我们也可以远离dynamic_cast,从而避免运行时的效率开销。



    在着手解决这个问题之前,我们先来考虑一个更为一般的问题。假设我们有2个任意类型UT,如何确定T能否自动转换成U呢?

    答案也许让你有些惊讶,我们可以利用sizeof来帮忙。你可以把sizeof用在任何复杂的表达式上, sizeof可以返回这个表达式值的大小,而不会在运行时评估表达式的值。这也就意味着,你可以把函数重载、模版实例化、转换规则等等所有你可以在C++表达式中使用的设施统统塞到sizeof中来。实际上,sizeof隐藏了一个可以演绎表达式类型的设施,最终,sizeof会返回表达式结果的类型。

    这样我们就可以通过sizeof和重载函数来解决判断类型之间的可转换性的问题。思路很简单:我们提供2个重载函数,一个函数的参数是我们要转换成的类型(我们用U表示),而另一个则用来接收其他所有类型的参数。然后我们把要检测的类型(用T表示)传递给重载函数。如果接受类型U为参数的函数被调用了,我们就认为T可以转换为U,反之则不可以。如何确定哪个函数被调用了呢?我们利用sizeof出马,我们只要让重载函数返回不同的类型,然后检查一下返回值就可以了。

    实践一下:

    首先,定义2个不同的类型:

    typedef  char  Small;
    class  Big  char  dummy[ 2 ]; } ;

    默认情况下, sizeof(Small) 1 ,而 Big 的大小则无关紧要,我们只要知道肯定不是 1 就好了。

    其次,定义 2 个重载函数,一个接收要转换成的类型:

    Small Test(U);

    另一个用来接收“其他的所有类型”,我们要保证在排除所有的转换之后才调用这个函数, OK, 用省略号表示的参数列表真好满足需求

    Big Test(...);

    尽管把一个 C++ 对象传递给 ... 参数类型的函数,其结果未定义,但是实际上我们并没有调用这个函数。我们甚至可以不用实现它。

    最后,我们用 sizeof 判断一下就完成任务了:

    const   bool  convExist  =   sizeof (Test(T()))  ==   sizeof (Small);

    你也许会说,就是它了! Test 的调用会创建一个临时对象 T ,之后可能的结果只能是 sizeof(Small) sizeof(Big) 。兴奋之余,我们还要看到一个问题。如果 T 的构造函数被设计成 private ,我们就前功尽弃了。当然解决的方法也很简单,定义一个函数,让他返回类型为 T 的对象。

    T MakeT();
    const   bool  convExist  =   sizeof (Test(MakeT()))  ==   sizeof (Small);

    最后,把刚才的东西封装到一个类里:

    template  < class  T,  class  U >
    class  Conversion  {
        typedef 
    char  Small;
        
    class  Big  char  dummy[ 2 ]; } ;

        
    static  Small Test(U);
        
    static  Big Test();
        
    static  T MakeT();

    public :
        
    enum   { exist  =   sizeof (Test(MakeT()))  ==   sizeof (Small) } ;
    }
    ;

    另外,我们还可以设置另外一个常量 Conversion::SameType ,如果 T U 表示同一个类型,那么返回 true

    template  < class  T,  class  U >
    class  Conversion  {
        .. 
    as  above..
        
    enum   { sameType  =   false }
    }
    ;

    之后为同一个类型设计一个偏特化版本:

    template  < class  T >
    class  Conversion < T, T >   {
        
    enum   { exists  =   1 , sameType  =   1  } ;
    }
    ;

    最后,回到我们的主题,通过 Conversion 的帮助,我们可以来决定两个类型的继承性了。

    #define  SUPERSUBCLASS(T, U) \
        (Conversion
    < const  U * const  T * )::exists  &&  \
        
    ! Conversion < const  T * const   void *> ::sameType)

    U 继承于 T 或者 U T 是同一个类型的时候, SUPERSUBCLASS 返回 true 。总结一下,只有下面这 3 种情形 const U* 可以隐式转换到 const T*

    1.      T U 是同一个类型

    2.      T U 的任意一个基类

    3.      T void

    我们通过第 2 个测试屏蔽了最后一种情形。当然,如果你认为同一种类型也不算是继承关系的话,可以进一步严格其条件:

    #define  SUPERSUBCLASS_STRICT(T, U) \
        (SUPERSUBCLASS(T, U) 
    &&  \
        
    ! Conversion( const  T,  const  U)::sameType)
  • 相关阅读:
    day03 字符串
    day02 运算符和编码
    day01 初识Python
    windows 安装yaml支持和pytest支持等
    Python自动补全缩写意义
    关于python接口测试connect error
    关于Python的post请求报504错误
    python函数参数*args **kwargs
    利用Python语言Appium启动ios app
    shell 中| 用法
  • 原文地址:https://www.cnblogs.com/cutepig/p/1400173.html
Copyright © 2020-2023  润新知