• 虚基类设计 c++


    一个例子

    在这里插入图片描述

    首先大家看一个定义的一个虚基类
    所谓的虚基类,是指类内包含virtual关键字定义的成员函数

    class Abstract_base
    {
    public:
    	virtual ~Abstract_base();
    	virtual void interface() const =0;
    	virtual const char* mumble() const {return m_mumble;}
    protect:
    	char* m_mumble;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上述的虚基类有以下特点:

    • 虚的析构函数。(必须的,否则继承的类将没法完全析构,delete BasePointer, BasePointer实际指向的是子类)
    • 两个虚的函数
      • 一个是接口
      • 一个是const char成员
      • 一个成员变量

    这样的构造成员函数有什问题?
    本人的分析
    对于虚构造函数,似乎没问题;对于虚拟接口,也没问题,各个子类有自己的实现嘛;对于mumble,子类返回的时候,m_mumble进行了初始化?没有,因为子类没办法初始化 m_mumble, 除非用 Abstract_base::m_mumble这种方式。

    class Abstract_base
    {
        public:
        ~Abstract_base(){};   // not virtual functions
        virtual void interface() const{};
        virtual const char* mumble() const {return m_mumble;}
        protected:
        char* m_mumble;
    };
    class derived_from_base : public Abstract_base
    {
        public:
        derived_from_base()
        {
            cout <<"derived ctor" << endl;
        }
        ~derived_from_base() 
        {
            cout << "~ derived dtor" << endl;
        }
        void interface() const override{}
        const char* mumble() const override{ return "asdfsd";}
    };
    int main()
    {
        Abstract_base* b = new derived_from_base();
        delete b;
        return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    [Running] cd "c:\Users\ssas0e\" && g++ abstract_class.cpp -o abstract_class && "c:\Users\ssas0e\"abstract_class
    derived ctor
    
    [Done] exited with code=1 in 3.236 seconds
    
    • 1
    • 2
    • 3
    • 4

    子类初始化父类的Protect 成员

    class Abstract_base
    {
        public:
        ~Abstract_base(){};
        virtual void interface() const{};
        virtual const char* mumble() const {return m_mumble;}
        protected:
        char* m_mumble;
    };
    
    class derived_from_base : public Abstract_base
    {
        public:
        derived_from_base()
        {
            cout <<"derived ctor" << endl;
            char* p = new char[8];
            p[0] = '1';
            p[1] = '\0';
            Abstract_base::m_mumble = p ;
        }
    
        ~derived_from_base() 
        {
            cout << "~ derived dtor" << endl;
        }
    
        void interface() const override{}
        const char* mumble() const override{ return Abstract_base::mumble();}
        
    };
    
    int main()
    {
       // Abstract_base();
        derived_from_base b;
        cout << b.mumble() << endl;
        return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    运行结果:

    derived ctor
    1
    ~ derived dtor
    
    • 1
    • 2
    • 3

    书上的分析
    虽然这个class 被设计为一个抽象的base class(其中pure virtual function,使得abstract_base不可能拥有实例,),但它仍然需要一个显示的构造函数,以初始化器成员变量,m_mumble。如果没有这个初始化操作,子类得到的m_mumble是未经过初始化的。

    你可能会争辩说,也许Abstract_base的设计者意图让每一derived class提供m_mumble的初始值。然而如果是这样,derived class 的唯一要求就是Abstract_base必须提供一个带有唯一参数的protect constructor.

    Abstract_base::
    Abstract_base(char* mumble_value=0):m_mumble(mumble_value)
    {}
    
    • 1
    • 2
    • 3

    一般而言,class的data member应该被初始化,并且只能在constructor挥着在class种的其他member funtions中设定初始值。其他的操作会破坏封装性质,使class的维护和修改更加困难。

    当然,你也可能争辩说,设计的者的错误并不在于未提供一个explicit constructor,而是它不应该在抽象的base class中声明 成员变量(数据成员,非指针)。这是比较强有利的论点,(把interface与implement分离),但它并不是普世道理。因为将“被共享的数据”取出来放在Base class中,毕竟是一种正当的操作。

    读后评论
    这里作者认为,虚基类是可以放data member的,因为这个data member是可以共享的数据。但是作者认为,上述的设计,应该提供一个显示的构造函数,不然子类就需要像我最开始的那种 Abstract_base::m_mumble的方式去给父类的成员变量assign ,破坏编程的封装性

  • 相关阅读:
    智能语音和自然语言处理技术
    网工内推 | IT工程师,IA认证即可,五险一金,全勤奖,最高10k
    使用Python制作内马尔的胜利之舞代码版
    在PowerDesigner中应用达梦数据库
    Java Double doubleValue()方法具有什么功能呢?
    HashMap和Hashtable的详细区别
    el-table中添加switch 且绑定值为0和1
    韩国机器人公司Rainbow Robotics推出RB-Y1轮式双臂机器人
    实现修改el-table表格中的字体或背景颜色
    浅谈etcd服务注册与发现
  • 原文地址:https://blog.csdn.net/tortelee/article/details/127934317