在c++中,類物件的建立方式有兩種,一種是靜態建立類物件,如a a;另一種是動態建立類物件,如a* p = new a;
這兩種方式是有區別的:
靜態建立類物件:是指全域性物件,靜態物件,以及分配在棧區域內的物件,編譯器對它們的記憶體分配是在編譯階段就完成的,是通過直接移動棧頂指標,挪出適當的空間,然後在這片記憶體空間上呼叫建構函式形成乙個棧物件。使用這種方法,直接呼叫類的建構函式。
動態建立類物件:分配堆區域內的物件,編譯器對他們的記憶體分配是在執行時動態分配的,(使用new運算子將物件建立在堆空間中。這個過程分為兩步,第一步,執行operator new()函式,在對中搜尋合適的記憶體並進行分配,第二步,呼叫建構函式構造物件,初始化這片記憶體空間。使用這種方法,間接呼叫類的建構函式。
知道了這些,那麼,如何限制類只能在堆上或棧上建立物件呢?
1.只能在堆上建立物件
類物件只能建立在堆上,就是不能靜態建立物件,即不能直接呼叫類的建構函式。
很容易就想到把類的建構函式宣告為私有,就無法在類的外部呼叫類的建構函式建立物件,只能使用new運算子來建立物件。前面已經說過,new運算子的執行過程分為兩步,c++提供new運算子的過載其實只是允許過載operator new()函式,不能過載new運算子,而operator new()函式只用於分配記憶體,無法提供建構函式,所以,我們再定義乙個getobj函式,用於在堆上new物件,通過getobj函式,建立的物件都是在堆上的new出來的,將函式宣告為靜態的,就可以通過域作用訪問符訪問getobj函式,在堆上建立物件。(在c++中靜態成員函式也是類函式,及這個函式不屬於某個具體的物件,而是屬於乙個類的,這個類例項化的每個成員都可用,同時,這個類也可以直接呼叫這個函式而不用例項化乙個物件。)
[cpp]
view plain
copy
"font-family:simsun;font-size:18px;"
>
class
bb
private
: bb(int
b1 = 0,
intb2 = 0)
:_b1(b1)
,_b2(b2)
{}
int_b1;
int_b2;
};
void
test()
網上還有一種說法,就是將析構函式宣告為私有的,當物件建立在棧上面的時候,是由編譯器分配記憶體空間
的,呼叫
建構函式來構造棧物件,當物件使用使用完之後編譯器會呼叫析構函式來釋放棧物件,編譯器管理了物件的
整個生命
週期,如果編譯器無法呼叫析構函式來釋放空間,那會發生什麼情況呢?比如,類的析構函式是私有的,編
譯器無法
呼叫析構函式來釋放記憶體。所以,編譯器在為類物件分配棧空間的時候,會先檢查類的析構函式的訪問性,
不只是析
構函式,只要是非靜態的函式,編譯器都會檢查,如果類的析構函式是私有的,那麼編譯器就不會在棧上位
類物件分
配記憶體。
那麼,到底為什麼將析構函式宣告為私有的就可以只在堆上建立物件呢?
因為c++是乙個靜態繫結的語言,在編譯過程中,所有的非虛函式都必須分析完成,即使是虛函式,也需檢查可訪問
性,因此,當在棧上生成物件是,物件會自動析構,也就是說析構函式必須可訪問,而對上生成物件,由於析構是由
程式設計師控制,所以,就可以不用析構函式,而重新定義乙個函式完成析構函式的功能,然後手動呼叫。
[cpp]
view plain
copy
class
aa
protected
: ~aa()
{}
};
void
test()
那麼怎麼釋放它呢? 析構函式私有化的類的設計可以保證只能用new命令在堆(heap)中建立物件, 只能動態的去建立物件, 這樣可以自由的控制物件的生命週期. 但是, 這樣的類需要提供建立和撤銷的公共介面.
[cpp]
view plain
copy
aa::
void
destory()
上述方法的乙個缺點就是,無法解決繼承問題。如果a作為其它類的基類,則析構函式通常要設為virtual,然後在子類重寫,以實現多型。因此析構函式不能設為private。還好c++提供了第三種訪問控制,protected。將析構函式設為protected可以有效解決這個問題,類外無法訪問protected成員,子類則可以訪問。
這就證明了,如果要建立乙個只能在堆上建立物件的類,無論將它的建構函式宣告成私有還是析構函式宣告為保護都可以達到這樣的目的,但是,如果將該類的建構函式或析構函式宣告為保護,最好將另外乙個也宣告為保護,因為例如你用new建立乙個物件, 卻不是用delete去刪除它, 而是要用destroy方法,很顯然,這是一種很奇怪的使用方法,所以,如果將該類的建構函式或析構函式宣告為保護,最好將另外乙個也宣告為保護。
2.只能在棧上建立物件的類
只有使用new運算子,物件才會建立在堆上,所以只要禁用new運算子就可以實現類物件只能建立在棧上,將operator new()設為私有就可以了,一定要記得,過載了new就要過載delete
[cpp]
view plain
copy
class
cc
~cc()
{}
private
: void
* operator
new(
size_t
)//過載operator new() ,注意函式返回值和引數都是固定的
{}
void
operator
delete
(void
* ptr)
//也要過載operator delete()
{}
};
**:參考:
設計乙個類,只能在棧上建立物件
設計乙個類,只能在棧上建立物件 思考的幾個要點 1 只能在棧,說明不能在堆上建立,考慮堆上建立物件的兩種方法 new和定位new表示式,原理 先呼叫operator new開空間,然後執行建構函式 所以遮蔽掉operator new 即放成私有 這樣就排斥了直接new和定位new表示式 注意 上面的...
如何定義乙個只能在棧上(對上)建立物件的類
1 只能在堆上生成物件 將析構函式設定為私有。原因 c 是靜態繫結語言,編譯器管理棧上物件的生命週期,編譯器在為類物件分配棧空間時,會先檢查類的析構函式的訪問性。若析構函式不可訪問,則不能在棧上建立物件。2 只能在棧上生成物件 將new 和 delete 過載為私有。將new操作設定為私有,那麼第一...
設計乙個類,只能在堆上建立物件
設計乙個類 只能在堆上建立物件 思路 說明不能在棧上建立物件,考慮到棧上建立物件會發生哪些事 1 建構函式 2 拷貝構造 所以先遮蔽掉建構函式,即設為私有。存在問題 在堆上建立物件也會呼叫建構函式,設為私有對其有影響 解決 提供成員函式介面,在成員函式中建立堆物件。存在問題 成員函式需要物件來呼叫,...