只在此山中,雲深不知處
Pointers
- 在C++中,電腦的記憶體就像一個個的區塊(byte),每個區塊有固定的位址(address),程式可以直接操控一塊記憶體( memory cells with consecutive addresses >> 可以超過1 byte)。
Address-of operator (&)
- 每個變數接儲存在電腦的某一塊記憶體內,該記憶體有特定位址。
-
將&加在某變數名稱,變成表示該變數的位址,否則只表示該變數的值。e.g.
- 此例中&add_a表示變數a在記憶體的位址,而add_a則表示該位址所儲存的值(也就是a),當add_a被改變時,a也隨之改變(反之亦然),因為是指的同一塊記憶體。
- 而val=a;則表示val得到a的值的copy,但是val與a分別儲存在兩塊不同的記憶體。
- 在取得某變數的reference時,兩者必須有相同的type(e.g. 皆為int),若有const修飾,則兩者皆須有const修飾(e.g. const int a = 10; const int &add_a = a;)。
- 可以refer to常數,但是必須使用const修飾,e.g. const int &add_a1 = 50;。
Dereference operator (*)
- 儲存某一變數(或物件)的位址的變數稱為pointer。
-
將*加在某變數之前,表示該變數為pointer,指向被指派的變數。e.g.
Dynamic memory
- 在某些情況下,程式所需要的記憶體大小無法確認,此時可以配置動態記憶體。
-
使用關鍵字new將記憶體配置給pointer變數,在使用完之後,需要將記憶體釋放,歸還給系統,此時需使用delete關鍵字。
- 系統配置一塊int大小的記憶體給p,並給初值100。這樣就不用先宣告一個int,在取得位址(&),然後指派給p。
- new會配置記憶體,所以要指派給pointer變數。
-
之前提到array的做法是需先宣告一個已知長度的array,然後將其位址指派給一個pointer,若是不確定array長度,可以使用new。
- arraysize也可以配置成pointer,e.g. int *arraysize=new int(0);。
-
配置記憶體有可能失敗,處理方式通常可以拋出(throw)例外(bad_alloc exception)或中止程式。另一個方式是讓pointer變成null pointer,此時使用關鍵字nothrow。
- 將(nothrow)關鍵字加在宣告pointer的new後方,之後判斷是否pointer等於nullptr,若是則表示配置失敗。
-
再來試試看2D array的做法。
- 其實就是變成1D的記憶體長度,算出每塊記憶體在2D array的位置即可。
Class
- 在設計class時使用pointer。
-
destructor: 當設計class時配置了記憶體,可設計destructor,在程式結束後負責釋放記憶體。
- destructor ~Aclass(){delete x;}用來在程式結束後刪除配置之記憶體。
- Aclass(): x(new int){}等同於Aclass(){x = new int();}。
-
polymorphism。
- 此例主要要說明的是繼承而來的class與被繼承的class兩者的pointer型態是相容的(e.g. Animal *dog = &lucky;)。
- 使用dog->setName("Lucky");等同於lucky.setName("Lucky");。
-
virtual members。
- 因為動物都會鳴叫,所以設計virtual函數call(),在繼承的class處可以覆寫此方法。
- 因為unknown animal的call()函數其實沒有使用的必要,所以可以將其設為abstract,將virtual函數修改為virtual string call()=0;即可。
- 請注意有abstract方法後,class Animal無法被宣告、使用其中的函數。但其pointer還是可以使用非virtual函數(e.g. dog->getName();)。
-
之前的例子若是繼承constructor,需使用new來配置記憶體。
- 使用Animal *lucky = new Dog("Lucky");語法來配置記憶體,在使用後記得使用delete釋放出記憶體。