c++ 語法中, 正常變數, 別名 & 變數和無名 &&變數的重要觀念:
1. 等號右邊(來源物件)必定是一個實體物件, 當它沒有具體名稱時稱為無名物件, 際上編譯器視需要會產生唯一識別碼當作名稱, 可以理解成用 && 來代表無名變數
2. 一旦實體化後賦予一個名稱, 就是具名物件, 也就是正常變數.
3. 如果宣告變數前置 & 符號, 代表的是別名, 它並不會產生新物件, 只是賦予一個名稱去共用等號右邊的資源, 可以理解成用 & 來代表別名變數.
4. 當用等於 = 符號指定物件時, 如果等號左邊(目標物件)的變數名稱未曾實體化過, 就會先呼叫建構式去產生物件, 再指定給該變數, 該變數就成為具名物件. 也就是正常變數
5. 如果傳進建構式的來源物件是無名物件(T &&), 則呼叫移動型建構式, 如果是具名物件(T &)則呼叫複製型建構式
6. 如果用等於 = 符號指定物件時, 如果等號左邊的變數(目標物件)曾經實體化過, 意味著要根據來源物件去更新目標物件的內容
7.如果實體化的目標物件, 用等於 = 符號指定新物件, 則會呼叫等號 = 運算式, 根據來源物件, 如果是無名物件(T &&)則呼叫移動型運算式: operator =(T &&), 如果是具名物件(T &)則呼叫複製型運算式: operator (T &), 去更新目標物件的內容
#include <stdio.h>
#include <iostream>
int main(){
int a=3; // 3 是無名整數 &&, 建構新的物件 a = int(3), 之後無名變數 && 自動消滅
int b=a;// 建構新的物件 b = int(a), a, b 是正常變數, 但 b 與 a 不同實體
int &c=b; // c 只是 b 的別名, b 與 c 共用一個實體
int &&d=std::move(a); // d 與 a 共用實體, 等同於 int &d = a; 但 d 不會消滅
printf("\na=%d\n",a); // 不同於無名的 3
printf("b=%d\n",b); // 不同於 a 的 3
printf("c=%d\n",c); // 等同於 b 3
printf("d=%d\n",d); // 等同於 a 的 3
d=4;
c=2;
printf("\na=%d\n",a); // 4, a 內容跟著改變
printf("b=%d\n",b); // 2, b 內容跟著改變
printf("c=%d\n",c); // 2, c 也變了
printf("d=%d\n",d); // 4, d 也變了
多變數指向相同位置時, 意味著該位置被多個變數參照(reference). 取出變數的參考位址要在變數前面加上 & 符號(注意與別命變數之差異: 別名變數放在目標物, 位址擷取則是在來源物), 取出指標的內容值則要在變數前慣上 * 符號.
int a; // a 是一般變數, &a 就是該變數的參考位址
int* ptr; // ptr 是指標變數, *ptr 就是指標的內容, 因此宣告成 int *ptr; 也無妨
ptr = &a;// 指標變數必須先初始化, 將 ptr 指向 a 的位置後, *ptr 與 a 的內容相同
如果覺得主角 * 太難理解, 用符號 & 可以宣告 a 的別名(alias) 變數 b(註: 必須用符號 = 同時去初始化)
int a;
int& b = a;// 也可以宣告成 int &b=a; 也就是指定 b 是 a 的別名(名稱不同).
一旦理解了指標與別名, 那指標的別名就容易多了, 為了要取出指標物件的主角, 只要在指標前慣上星號 * 就是變數的內容:
#include "stdio.h"
int main() {
int* a; // a 是指標變數
int* &b = a; // b 也是指標變數, 只不過初始化時為 a 的別名, 不管用 int*& b = a; 或 int *&b = a; 結果都相同
int c = 3; // c 的內容等於 3
b = &c; // 既然 b 是 a 的別名且又是指標變數, 可以把 b 指向 c , 等同把 a 指向 c
printf("*a = %d\n", *a);// 因此取出 a 的內容等同取出 b 的內容, 也就是 c 的內容: 3
}
宣告一個 * 的指標變數, 它就類似一維陣列, 而陣列就是一個固定連續空間, 但宣告陣列與宣告指標變數不同的是: 陣列會分配出記憶空間但指標不會, 而指標變數可以任意定位, 陣列卻不可以.因此兩者用法並不相同, 其實不可混淆.
int *ptr; // 實體位置未指定, 初始化之前都不得使用
int dim[ ] = {1,2,3}; // 分配出 3 個整數的空間
ptr = dim; // 但 ptr 可以指向相同型態的陣列
至於連續兩個 ** 也就是連續的指標空間(類似儲存指標的陣列)
int a[ ] = {1,2,3}; // a 內容陣列是整數, a 其實是指標, 只是不能重定位
int b[ ] = {4,5,6}; // b 也是整數陣列, b 是指標
int* ab[ ] = { a, b }; // ab 是儲存整數指標的陣列
int** pab; // 宣告整數型態的二維指標 pab
pab = ab; // pab 可以指向 ab
上述 int** pab 也可宣告成 int* *pab甚至 int **pab, 運算結果都一樣, 當 pab 指向 ab 之後, 實際上 pab[0] 內容就是 a , pab[1] 為 b, 而 **pab 則為 pab[0][0], 因此全部內容展開就是:
pab[0][0] = 1, pab[0][1] =2 , pab[0][2] = 3
pab[1][0] = 4, pab[1][1] =5. pab[1][2] = 6
函式的參數如果是以函數型式, 稱為無名函數(annonymous function vaule)傳進來, 就用符號 && 代表無名, 尤其在 move constructor 一定會用到. 最後要注意的是主角與別名 & 甚至無名 && 等變數代表了一個實體物件, 針對類型成員要是用句號 . 取用物件資源, 但 *, *&, ** 等指標變數必須經過初始化後再用星號 * 轉回物件, 或用中括號取得陣列中的物件, 類型的指標變數要另外用箭號 -> 取用物件成員. 在類型中 *this 是物件主角, 但 this 是物件的指標.
1 則留言:
初学者程序员的c ++示例代码
将一个或多个文件复制到一个文件中
張貼留言