void*指針
void關鍵字表示“空類型”的概念。但是,這里的“空類型”不表示“任意類型”,而是表示不存在的意思,也就是說C/C++不允許你寫語句void a,不存在類型為void的東西.
void*表示“空類型指針”,與void不同,void*表示“任意類型的指針”或表示“該指針與一地址值相關,但是不清楚在此地址上的對象的類型”。
類型轉換
C風格轉換:
1 int i; 2 double d; 3 4 i = (int) d; 5 //或 6 i = int (d);
C風格轉換在C++中是適用的。但是C++也提供了4種轉換方法。
那為什么還需要一個新的C++類型的強制轉換呢?
新類型的強制轉換可以提供更好的控制強制轉換過程,允許控制各種不同種類的強制轉換。C++中風格是static_cast<type>(content)。C++風格的強制轉換其他的好處是,它們能更清晰的表明它們要干什么。程序員只要掃一眼這樣的代碼,就能立即知道一個強制轉換的目的。
C++轉換:
static_cast(exp)
用於相關類型之間的轉換,諸如:在同一個類的繼承層次關系中,向上或向下轉換;枚舉類型與整數類型之間的轉換;浮點類型與指數類型之間的轉換。
static_cast它能在內置的數據類型間互相轉換,對於類只能在有聯系的指針類型間進行轉換。可以在繼承體系中把指針轉換來、轉換去,但是不能轉換成繼承體系外的一種類型
1 class A { ... }; 2 class B { ... }; 3 class D : public B { ... }; 4 void f(B* pb, D* pd) 5 { 6 D* pd2 = static_cast<D*>(pb); // 不安全, pb可能只是B的指針 7 B* pb2 = static_cast<B*>(pd); // 安全的 8 A* pa2 = static_cast<A*>(pb); //錯誤A與B沒有繼承關系 9 ... 10 }
reinterpret_cast(exp)
字面理解即re-interpret,重新解析(釋)的意思。故名思意,它主要用於不相關類型之間的轉換,好一個英文單詞在不同的上下文中,詞性和詞義可能完全不同。它為不同類型之間轉換帶來的便利,但是也伴隨着風險的,如將一個十六進制整數轉換為內存地址(由int-->指針類型,這兩種類型完全不關聯)。既然是用於不相關類型之間的轉換,也就意味着編譯器不會做太多的確認和承諾。
reinterpret_cast方式還有一個特點就是:目標和原始值之間至少有相同的位數,我們可以將轉換之后的值再轉換回去,而不像其它3種類型可能會導致精度丟失。
dynamic_cast(exp)
一種運行時(run-time)檢測的類型轉換,因此轉換可能需要較大的運行時代價,這種類型也是用C-style是無法實現的。主要用於執行類型向下轉換和繼承之間的轉換。
dynamic_cast 僅能應用於指針或者引用,不支持內置數據類型
表達式dynamic_cast<T*>(a) 將a值轉換為類型為T的對象指針。如果類型T不是a的某個基類型,該操作將返回一個空指針。
它不僅僅像static_cast那樣,檢查轉換前后的兩個指針是否屬於同一個繼承樹,它還要檢查被指針引用的對象的實際類型,確定轉換是否可行。
const_cast(exp)
用於消除變量的const限定,轉換之后的變量就不再具有“const”了,如果是一個const指針的話,轉換之后可以改變指向而指向其它對象。
說明:
通常情況下dynamic_cast最好些,它檢查的更嚴格些,其次是static_cast,而后兩者也就是const_cast和reinterpret_cast較之前兩者貌似不太常用,而且也不推薦使用,const_cast在用於去除const的地方還是有所發揮的,reinterpret_cast在轉換時,不會在內存中進行補足比特位(例如int轉換到double,需要補足4字節),這往往是不安全的,而且代碼也是不可移植的。
動態內存分配
一般來說,編譯器將內存分為三部分:靜態存儲區域、棧、堆。靜態存儲區主要保存全局變量和靜態變量,棧存儲調用函數相關的變量、地址等,堆存儲動態生成的變量。 在c中是指由malloc,free運算產生釋放的存儲空間,在c++中就是指new和delete運算符作用的存儲區域。
對象創建的兩種方式:
類示例:
1 #include <iostream> 2 using namespace std; 3 4 class TestNew 5 { 6 private: 7 int ID; 8 public: 9 TestNew(int ID); 10 ~TestNew(); 11 }; 12 13 TestNew::TestNew(int ID) 14 { 15 this->ID = ID; 16 } 17 18 TestNew::~TestNew() 19 { 20 std::cout<<"對象 "<<this->ID<<" 執行析構函數"<<std::endl; 21 }
方法一:
ClassName object(param);
1 TestNew test(1);
這樣就聲明了一個ClassName類型的object對象,C++會為它分配足夠的存放對象所有成員的存儲空間。
這種方法創建的對象,內存分配是分配到棧中的,由C++缺省創建和撤銷,自動調用構造函數和析構函數。
該方法創建的對象調用類方法時,必須用“.”,而不能用“->”。
在函數中使用該方法時,函數內局部變量的存儲單元都在棧上創建,函數執行結束后在將這些局部變量的內存空間回收。
在棧上分配內存空間效率很高,但是分配的內存容量有限。
方法二:
ClassName *object=new ClassName(param);
delete object;
1 TestNew *pTest = new TestNew(1); 2 delete pTest;
C++用new創建對象時返回的是一個對象指針,object指向一個ClassName的對象,C++分配給object的僅僅是存放指針值的空間。
用new 動態創建的對象必須用delete來撤銷該對象。只有delete對象才會調用其析構函數。
new創建的對象不是用“*”或“.”來訪問該對象的成員函數的,而是用運算符“->”;
new創建類對象特點:
- new創建類對象需要指針接收,一處初始化,多處使用
- new創建類對象使用完需delete銷毀
- new創建對象直接使用堆空間,而局部不用new定義類對象則使用棧空間
- new對象指針用途廣泛,比如作為函數返回值、函數參數等