1. 程式人生 > >設計一個類只能在堆(棧)上建立

設計一個類只能在堆(棧)上建立

在C++中,建立類的物件有兩種方法,一種是靜態建立,A a; 另一種是動態建立,呼叫new 操作符。

靜態建立一個類物件,是由編譯器為物件在棧空間中分配記憶體,是通過直接移動棧頂指標,挪出適當的空間,然後在這片記憶體空間上呼叫建構函式形成一個棧物件。使用這種方法,直接呼叫類的建構函式。

動態建立類物件,是使用new運算子將物件建立在堆空間中。這個過程分為兩步,第一步是執行operator new()函式,在堆空間中搜索合適的記憶體並進行分配;第二步是呼叫建構函式構造物件,初始化這片記憶體空間。這種方法,間接呼叫類的建構函式。

1、只能在堆上建立物件的類

那就是動態建立類的物件,使用new操作符來完成。
所以可以這樣做,將該類的建構函式和解構函式許可權設為protected,(可以讓該類可以被繼承

),然後定義兩個static 函式來呼叫new ,delete 來建立和銷燬物件。

//設計一個類只能在堆上建立物件
//在堆上建立物件,需要使用new,使用靜態成員函式建立物件和銷燬
//將建構函式和解構函式宣告為protected,是為了讓該類可以被繼承
class A
{
protected:
    A(){}
    ~A(){}
public:
    static A* Create()
    {
        return new A();
    }
    static void Destroy(A* p)
    {
        delete p;
        p = NULL;
    }
};

方法二:將解構函式宣告為私有的

這是我在網上看到的另一種方法

為什麼將解構函式設為私有的,就可以只能在堆上建立?

物件建立在棧上面時,是由編譯器分配空間的,呼叫建構函式來構造棧物件,當物件使用完之後,編譯器會呼叫解構函式來釋放棧物件所佔的空間,編譯器管理了物件的整個生命週期,編譯器為物件分配空間的時候,只要是非靜態的函式都會檢查,包括解構函式,但是此時解構函式不可訪問,編譯器無法呼叫類的解構函式來釋放記憶體,那麼編譯器將無法在棧上為物件分配記憶體。

那麼如何釋放它呢? 答案也很簡單, 提供一個成員函式, 完成delete操作. 在成員函式中, 解構函式是可以訪問的, 當然detele操作也是可以編譯通過.

class a
{
public :
    a(){}
    void destory()
    {
        delete this;
    }
private:
    ~a(){};
};

方法二兩個缺點:(1)無法解決繼承問題,因為通常情況之下a作為基類,一般解構函式要設為vitual,然後子類重寫,已實現多型,因此解構函式不能設為private,不過c++還有protected訪問控制方式,將解構函式設定為protected,這樣子類可以訪問,但是類外無法訪問。(2)使用不方便,不統一,因為你使用了new創造了物件,但是不能使用delete釋放物件,必須使用destory函式,這種方式比較怪異,所以我們也可以將建構函式設定為protected,同時提供另一public static create()函式來進行替代new。這樣 create()建立物件在堆上, destory()釋放記憶體。
這樣 其實 還是和方法一差不多。

2、只能在棧上建立物件的類

只能在棧上建立的物件的話,就是不能呼叫new 操作符,所以可以將operator new 和operator delete 設定為私有的。

//設計一個類只能在棧上建立物件,
//不能呼叫new 操作符,過載operator new() 和 operator delete()

class B
{
private:
    void * operator new(size_t size){}
    void operator delete(void *ptr){}

public:
    B(){}
    ~B(){}
};