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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM