• 模板与继承之艺术——空基类优化


    1、概念
    C++中有“空”类的概念,这就意味着在运行期间其内部不好任何内存。
    只包含类型的成员函数、非虚成员函数和静态数据成员的类为空类。
    非静态的数据成员,虚函数和虚基类则在运行时期消耗存储空间。
    2、空基类优化如下:
    #include<iostream>
    using namespace std;
    class Empty{
         typedef int Int;
    };
     
    class EmptyToo : public Empty
    {};
    class EmptyThree : public EmptyToo
    {};
    int main()
    {
        cout << "sizeof(Empty):" << sizeof(Empty) << endl;
        cout << "sizeof(EmptyToo):" << sizeof(EmptyToo)<< endl;
        cout << "sizeof(EmptyThree):" << sizeof(EmptyThree) << endl;
    }
    (1)在类EmptyToo中类Empty没有分配存储空间
    (2)带有优化空基类的空类作为被继承的基类(没有其他基类时,单继承)时,其大小也为0,这也就是EmptyTree 能和Empty具有相同大小的原因所在。
     
    3、如果有其他基类时:
    #include<iostream>
    class Empty{
        typedef int Int;
    };
     
    class EmptyToo : public Empty{};
     
    class EmptyThree : public Empty, public EmptyToo{};
    int main()
    {
        cout << "sizeof(Empty):"<< sizeof(Empty) << endl; //输出1
        cout << "sizeof(EmptyToo)" << sizeof(EmptyToo)<< endl; //输出1
        cout << "sizeof(EmptyThree):" << sizeof(EmptyThree) << endl; //输出2
    }
     
    如果继承时是多重继承:
    EmptyThree中有两个不同的子类Empty对象,一个是直接继承来的Empty对象,另一个是EmptyToo继承来的Empty对象。
    由于是两个对象所以不能让其有相同的地址空间。即这里优化(2)不起作用,EmptyThree是两个Empty和EmptyToo大小之和。
     
    4、将成员作为基类
    只举一例,模板参数确定会被实例化为类型(不是非类型,不是原生类型比如int),该模板类的另一个成员类型不是空类。如下:
    template<typename CustomClass>
    class Optimizable{
        private:
          CustomClass info;
          void* storage;
    };
     
    改写为:
    template <typename CustomClass>
    class Optimizable {
        private:
           BaseMemberPair<CustomClass, void*> info_and_storage;
    };
     
    //
    template<typename Base, typename Member>
    class BaseMemberPair : private Base{
        private:
             Member member;
    public:
             BaseMemberPair(Base const &b, Member const &m):Base(b), member(m){}
    //通过first来访问基类数据
    Base const&  first() const{ return (Base const&)*this; }
    Base& first() const { return (Base&)*this; }
     
    //通过second()来访问成员变量
    Member const& second() const { return this->member; }
    Member& second() const { return this->member; }
    };
     
    优化前:
    #include<iostream>
    using namespace std;
    
    template<typename CustomClass>
    class Optimizable{
        private:
          CustomClass info;
          void* storage;
    };
    class Test{
    };
    int main()
    {
        cout << sizeof(Optimizable<Test>) << endl;
     //结果为8
        return 0;
    }
    View Code

    优化后:

    #include<iostream>
    using namespace std;
    
    template<typename Base, typename Member>
    class BaseMemberPair : private Base{
        private:
             Member member;
    public:
             BaseMemberPair(Base const &b, Member const &m):Base(b), member(m){}
    //通过first来访问基类数据
    Base const&  first() const{ return (Base const&)*this; }
     //提供给const对象调用
    Base& first() { return (Base&)*this; }
    
    //通过second()来访问成员变量
    Member const& second() const { return this->member; }
    Member& second() { return this->member; }
    };
    
    template <typename CustomClass>
    class Optimizable {
        private:
           BaseMemberPair<CustomClass, void*> info_and_storage;
    };
    
    class Test{
    };
    int main()
    {
        cout << sizeof(Optimizable<Test>) << endl;
    //结果为4
        return 0;
    }
    View Code

    5、警告:

    针对下面的情况:
    template<typename T1, typename T2>
    class MyClass{
          private:
          T1 a;
          T2 b;
    };
    //优化
    template<typename T1, typename T2>
    class MyClass : private T1, private T2{};
     
    在不知道T1和T2是否为类型的情况下,最好不要盲目使用上面的优化方法,因为:
    (1)此方法不适用于原生类型int等
    (2)如果T1, 和T2的类型相同继承会出问题。
    (3)增加基类会改变接口,因为多重继承,如果T1和T2都有共同的基类Base的话,那么MyClass中的数据成员,成员函数将会有二义性。所以此方法最好适应是之前提演示出的情况。
     
    编辑整理:Claruarius,转载请注明出处。
  • 相关阅读:
    收集座右铭
    Yii2查询语句使用不等于号
    使用jQuery获取Bootstrap Switch的值
    wamp 提示 Directive allow_call_time_pass_reference is no longer avaiable in PHP
    解决GitHub添加sshkey仍然无法访问clone远程仓库的问题
    异常-User class threw exception: java.lang.IllegalStateException: Cannot call methods on a stopped SparkContext.
    CDH5.16.1升级kafka0.10到1.0.1
    MacOs桌面自动被打乱的原因
    彻底解决MacOS上应用程序快捷键冲突的问题,自定义快捷键设置
    CDH5.16.1的maven依赖版本查询地址
  • 原文地址:https://www.cnblogs.com/claruarius/p/4111581.html
Copyright © 2020-2023  润新知