zoukankan      html  css  js  c++  java
  • C++ 句柄类

    一、容器与继承

        在容器中保存有继承关系的对象时,如果定义成保存基类对象,则派生类将被切割,如果定义成保存派生类对象,则保存基类对象又成问题(基类对象将被强制转换成派生类对象,而派生类中定义的成员未被初始化)。

        唯一的可行的选择是容器中保存对象的指针。但是需要用户管理对象和指针。C++中一个通用的技术是包装类(cover)或句柄类(handle)。用句柄类存储和管理类指针。

         句柄类大体上完成两方面的工作:

    1. 管理指针,这与智能指针的功能类似。

    2. 实现多态,利用动态绑定,是得指针既可以指向基类,也可以指向派生类。

         包装了继承层次的句柄有两个重要的设计考虑因素:

    1. 像对任何保存指针的类一样,必须确定对复制控件做些什么。包装了继承层次的句柄通常表现得像一个智能指针或者像一个值。

    2. 名柄类决定句柄接口屏蔽还是不屏蔽继承层次,如果不屏蔽继承层次,用户必须了解和使用基本层次中的对象(objects in theunderlying hierarchy)。

    下面通过一个我自己写的一个简单的例子来说明这个问题:

        这个例子程序包括一个基类,一个派生类,还有一个句柄类。

        其中,基类有2个私有成员,数值m_base和程序名字name。派生类有一个新的私有成员,m_der。

        派生类和基类有虚函数compute。基类的compute它计算基类成员m_base平方。派生类的compute计算m_base平方和m_der之和。

        句柄类有两个数据成员,分别是指向引用计数的指针( 这里必须是指针,复制时引用计数复制指针的值,保证一个实例化对象只有一个引用计数)和指向基类或者是其派生类的指针。

    #include<iostream>
    #include<string>
    #include<exception>
    using namespace std;
    // base class
    class Base {
    public:
        //basic constructor
        Base(int m_base = 1, string name = "Base")
                : m_base(m_base), name(name) {
            cout << "Base constructor called!" << endl;
        }
        //copy constructor
        Base(const Base &base) : Base(base.m_base, base.name) {
            cout << "Base copy called" << endl;
        }
        virtual Base *clone() const {
            return new Base(*this);
        }
        const string getName() {
            return name;
        }
        virtual int compute() const {
            return m_base * m_base;
        }
        virtual ~Base(){
            cout<<"Base deleted"<<endl;
        }
    protected:
        int m_base;
        string name;
    };
    class Derived : public Base {
    public:
        //basic constructor
        Derived(int m_base, string name, int m_der)
                : Base(m_base, name), m_der(m_der) {
            cout << "Derived constructor called" << endl;
        }
        //copy constructor
        Derived(const Derived &derived) : Derived(derived.m_base, derived.name, derived.m_der) {
            cout << "Derived copy called" << endl;
        }
        virtual Derived *clone() const {
            return new Derived(*this);
        }
        virtual int compute() const {
            //调用父类中定义的方法
            return Base::compute() + m_der;
        }
        virtual ~Derived(){
            cout<<"Derived deleted"<<endl;
        }
    private:
        int m_der;
    };
    class Handler {
    public:
        //默认构造函数
        Handler() : pBase(NULL), use(new int(1)) { }
        //一般构造函数
        Handler(const Base &item) : pBase(item.clone()), use(new int(1)) { }
        //复制构造函数
        //每复制一次,引用计数就加1
        Handler(const Handler &ref) : pBase(ref.pBase), use(ref.use) {
            ++*use;
        }
        //重载赋值操作符
        Handler &operator=(const Handler &right) {
            ++*(right.use);
            decrese_use();
            pBase = right.pBase;
            use = right.use;
            return *this;
        }
        //重载箭头操作符
        const Base *operator->() const {
            if (pBase)
                return pBase;
            else
                throw logic_error("unbound Handler!");
        }
        //重载解引用操作符
        const Base &operator* () const{
            if(pBase)
                return *pBase;
            else
                throw logic_error("unbound Handler");
        }
        void print_use() {
            cout << pBase->getName() << " use: " << *use << endl;
        }
        //析构函数
        ~Handler() {
            decrese_use();
        }
    private:
        //此处必须使用指针,保证一个Base实例只对应一个引用计数
        int *use;
        Base *pBase;
        void decrese_use() {
            if (--*use == 0) {
                cout << pBase->getName() << " is going to be deleted!" << endl;
                delete pBase;
            }
        }
    };
    int main() {
        Handler h1(Base(2,"Base"));
        h1.print_use();
        cout<<"Base compute:"<<(*h1).compute()<<endl;
        Handler h2(h1);
        h2.print_use();
        cout<<"Base compute:"<<(*h2).compute()<<endl;
        cout<<"-------------------------------------"<<endl;
        Handler h3(Derived(3,"derived",3));
        h1=h3;
        h1.print_use();
        cout<<"Derived compute:"<<(*h1).compute()<<endl;
        cout<<"system automatic delete begin"<<endl;
        return 0;
    }

    二、句柄类

        句柄类Handle 有3个构造函数:默认构造函数,复制构造函数,和接收基类Base对象的构造函数。为了保证 在接收基类Base对象的构造函数中 复制具体对象的时候实现动态调用,得到正确类别的实例,我们在类中定义了虚函数clone

    Base

    virtual Base *clone() const {
            return new Base(*this);
    }

    Derived

    virtual Derived *clone() const {
            return new Derived(*this);
    }

    三、运行结果   

    主函数调用:

    int main() {
        Handler h1(Base(2,"Base"));
        h1.print_use();
        cout<<"Base compute:"<<(*h1).compute()<<endl;
        Handler h2(h1);
        h2.print_use();
        cout<<"Base compute:"<<(*h2).compute()<<endl;
        cout<<"-------------------------------------"<<endl;
        Handler h3(Derived(3,"derived",3));
        h1=h3;
        h1.print_use();
        cout<<"Derived compute:"<<(*h1).compute()<<endl;
        cout<<"system automatic delete begin"<<endl;
        return 0;
    }

    输出:

    Base constructor called!
    Base constructor called!
    Base copy called
    Base deleted
    Base use: 1
    Base compute:4
    Base use: 2
    Base use: 2
    Base compute:4
    -------------------------------------
    Base constructor called!
    Derived constructor called
    Base constructor called!
    Derived constructor called
    Derived copy called
    Derived deleted
    Base deleted
    derived use: 2
    derived use: 2
    Derived compute:12
    system automatic delete begin
    Base is going to be deleted!
    Base deleted
    derived is going to be deleted!
    Derived deleted
    Base deleted

      主函数中使用Base对象创建了Handler对象h1,并由h1构造Handler对象h2,通过输出可以发现Handler对象的引用计数由1变为2。然后使用Derived对象创建Handler对象h3,并将其赋值给h1,对h1,h3 输出其引用计数,可知引用计数均为2.

  • 相关阅读:
    Ganglia与Centreon整合构建智能化监控报警平台
    通过Centreon监控apache、MySQL、Hadoop服务状态
    分布式监控告警平台Centreon快速使用
    分布式监控数据采集系统Ganglia实战
    Zabbix与ELK整合实现对日志数据的实时监控
    Zabbix通过与微信、钉钉整合实现实时告警
    详解容器设计模式
    深入理解 Pod
    docker exec实现原理
    使用Docker部署应用以及容器数据卷Volume
  • 原文地址:https://www.cnblogs.com/zhoudayang/p/5536630.html
Copyright © 2011-2022 走看看