從C到C++的過渡(2)
七、C++的動態記憶體分配
malloc/calloc/realloc/free 1、new/delete:對單個變數進行記憶體分配/釋放。 2、new[]/delete[]:對陣列進行記憶體分配/釋放。
#include <iostream> using namespace std; int main(){ //int* pi = (int*)malloc(sizeof(int)); //free(pi); int* pi = new int; *pi = 8; cout << *pi << endl; delete pi; pi = NULL; pi = new int[10]; for (int i = 0;i < 10;++i) pi[i] = i; for (int i = 0;i < 10;++i) cout << pi[i] << ' '; cout << endl; delete[] pi; pi = NULL; pi = new int(1234); cout << *pi << endl; delete pi; pi = NULL; char buf[4] = {0x12,0x34,0x56,0x78}; pi = new(buf) int;//定位new cout << hex << *pi << endl; cout << (void*)pi << ' ' << (void*)buf << endl; //delete pi;//此處不能delete,new的是棧的記憶體,不能delete int (*p)[4] = new int[3][4]; delete[] p; int (*q)[4][5] = new int[3][4][5]; delete[] q; return 0; }
八、C++的字串
可以直接宣告變數並進行賦值等字串操作。 C沒有字串專門機制,用char型陣列在末尾加’\0’的辦法來處理字串,C++也相容這種“C字串”機制。在C++中則把字串封裝成了一種資料型別string,來專門處理字串,它提供了非常豐富的字串處理功能。而且,string還提供了與“C字串”相互轉換的方法,使用非常靈活。
九、引用
1、引用即別名。 int a = 20; int& b = a; b = 10; cout << a << endl;//10 2、引用必須初始化。 int a; int* p; a = 20; p = &a; int& b;//ERROR int& b = a;//OK 3、引用一旦初始化就不能再引用其他變數。 int a = 20, c = 30; int& b = a; b = c;//ERROR 4、引用的應用場景 (1)引用型引數 a、修改實參 b、避免拷貝,通過加const可以防止在函式中意外的修改實參的值,同時還可以接受擁有常屬性的實參。 (2)引用型返回值 int b = 10; int a = func(b); func(b) = a; 從一個函式中返回引用往往是為了將該函式的返回值作為左值使用。但是,一定要保證函式所返回的引用的目標在該函式返回以後依然有定義,否則將導致不確定的後果。 不要返回區域性變數的引用,可以返回全域性、靜態、成員變數的引用,也可以返回引用型形參變數本身。 5、引用和指標 (1)引用的本質就是指標,很多場合下引用和指標可以互換。 (2)在C++層面上引用和指標存在以下不同: A、指標是實體變數,但是引用不是實體變數。 int& a = b; sizeof(a);//4 double& d = f; sizeof(d);//8 B、指標可以不初始化,但是引用必須初始化。 C、指標的目標可以修改,但是引用的目標不能修改。 D、可以定義指標的指標,但是不能定義引用的指標。 int a; int* p = &a; int** pp = &p;//OK int& r = a; int&* pr = &r;//ERROR E、可以定義指標的引用,但是不能定義引用的引用。 int a; int* p = &a; int*& q = p;//OK int& r = a; int&& s = r;//ERROR F、可以定義指標的陣列,但是不能定義引用的陣列。 int a,b,c; int* parr[] = {&a,&b,&c};//OK int& rarr[] = {a,b,c};//ERROR 可以定義陣列的引用。 int arr[] = {1,2,3}; int (&arr_ref)[3] = arr;//OK
十、顯式型別轉換運算子
C:目標型別變數 = (目標型別)源型別變數; 1、靜態型別轉換 static_cast<目標型別> (源型別變數) 如果在目標型別和源型別之間某一個方向上可以做隱式型別轉換,那麼在兩個方向上都可以做靜態型別轉換。反之如果在兩個方向上都不能做隱式型別轉換,那麼在任意一個方向上也不能做靜態型別轉換。 int* p1 = …; void* p2 = p1; p1 = static_cast<int*> (p2); 如果存在從源型別到目標型別的自定義轉換規則,那麼也可以使用靜態型別轉換。 2、動態型別轉換 dynamic_cast<目標型別> (源型別變數) 用在具有多型性的父子類指標或引用之間。 3、常型別轉換 const_cast<目標型別> (源型別變數) 給一個擁有const屬性的指標或引用去常 const int a = 100; const int* p1 = &a; p1 = 200;//ERROR int
十一、C++之父的建議
1、少用巨集,多用const、enum和inline #define PAI 3.14159 const double PAI = 3.14159;
#define ERROR_FILE -1 #define ERROR_MEM -2 enm{ ERROR_FILE = -1; ERROR_MME = -2; };
#define max(a,b) ((a) > (b) ? (a) : (b)) inline int double max(double a,double b){ return a > b ? a : b; } 2、變數隨用隨宣告同時初始化 3、少用malloc/free,多用new/delete。 4、少用C風格的強制型別轉換,多用型別轉換運算子。 5、少用C風格的字串,多用string。 6、樹立面向物件的程式設計思想。