C++ 句柄类

江枫雨发布

c++ 中多态只有通过对象的引用或指针调用时才生效,通过普通对象调用成员函数不支持多态。比如以下容器和多态的例子:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void name() const { cout << "Base" << endl; }
};

class BaseA : public Base {
public:
    virtual void name() const { cout << "Base A" << endl; }
};

int main() {
    // 对象直接调用,多态不生效
    vector<Base> bases;
    bases.push_back(Base());
    bases.push_back(BaseA());
    for (vector<Base>::const_iterator it = bases.begin(); it != bases.end(); it ++) {
        it->name();
    }

    // 指针调用,多态生效
    vector<Base*> basePtrs;
    basePtrs.push_back(new Base());
    basePtrs.push_back(new BaseA());
    for (vector<Base*>::iterator it = basePtrs.begin(); it != basePtrs.end(); it ++) {
        (*it)->name();
    }

    return 0;
}

输出:

Base
Base
Base
Base A

所以要让容器中的元素支持多态,必须通过保存对象指针。但这样做面临指针的管理,用户要保证容器存在时,存放的指针对象有效。

c++ 提供了对这类指针的封装称为句柄类。句柄类中包含基类指针类型的成员变量,以及对该指针的计数管理。当容器调用句柄类对象时,对象的指针成员支持多态。用户无须操心指针的管理。
句柄类的实现,类似于共享指针,实现共享指针的共享引用计数使用的是 int 指针,而不是额外的计数存储类。

#include <iostream>
using namespace std;

class Base {
public:
    virtual void name() const { cout << "Base" << endl; }

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

class BaseA : public Base {
public:
    virtual void name() const { cout << "Base A" << endl; }

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

class BaseHandle {
public:
    // 默认构造函数
    BaseHandle() : p(0), use(new int(1)) {}

    // 从 Base 引用初始化的构造函数
    BaseHandle(const Base &b) : p(b.clone()), use(new int(1)) {}

    // 复制构造函数
    BaseHandle(const BaseHandle &b) : p(b.p), use(b.use) { ++ *use; }

    // 赋值操作
    BaseHandle& operator=(const BaseHandle &rhs) {
        ++ *rhs.use;
        decr();
        p = rhs.p;
        use = rhs.use;
        return *this;
    }

    const Base* operator->() const {
        if (p) return p;
        else throw logic_error("unbound pointer");
    }

    const Base& operator*() const {
        if (p) return *p;
        else throw logic_error("unbound pointer");
    }

    ~BaseHandle() { decr(); }

private:
    Base *p;

    // 首先智能指针,通过定义为指针共享计数(另一种方式是新增共享指针计数类)
    int *use;

    void decr() {
        if (-- *use == 0) {
            delete p; delete use;
        }
    }
};

int main() {
    // 普通对象函数调用,多态不生效
    vector<Base> bases;
    bases.push_back(Base());
    bases.push_back(BaseA());
    for (vector<Base>::const_iterator it = bases.begin(); it != bases.end(); it ++) {
        it->name();
    }

    // 指针类型调用,多态生效
    vector<Base*> basePtrs;
    basePtrs.push_back(new Base());
    basePtrs.push_back(new BaseA());
    for (vector<Base*>::iterator it = basePtrs.begin(); it != basePtrs.end(); it ++) {
        (*it)->name();
    }

    // 句柄类型调用,多态生效,且句柄类自动管理指针对象(智能指针)
    vector<BaseHandle> handles;
    handles.push_back(BaseHandle(Base()));
    handles.push_back(BaseHandle(BaseA()));
    for (vector<BaseHandle>::iterator it = handles.begin(); it != handles.end(); it ++) {
        (*it)->name();
    }

    return 0;
}

输出:

Base
Base
Base
Base A
Base
Base A

句柄类用于配合容器元素支持多态,同时又无须用户自行管理指针。

分类: c++

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注