引用時C++的一個特性,它就像能自動被編譯器逆向引用的常量型指標一樣。C++中引用的思想來自Algol語言。引用是支援C++運算子多載文法的基礎,也為函數參數的傳入傳出控制提供了便利。拷貝建構函式是特殊的建構函式,需要用引用來實現從現有的相同類型的對象產生新的對象。編譯器用拷貝建構函式通過傳值方式來傳遞和返回對象。
C和C++指標的區別在於,C++是一種類型要求更強的語言。C不允許隨便把一個類型的指標指派給另一個對象,但允許通過void*來實現。C++是不允許這樣做的。
引用(&)像一個能被編譯器逆向引用的常量指標。通常使用者函數的參數表或函數的傳回值。但也可以獨立使用。當建立引用時,引用必須被初始化執行一個存在的對象。引用必須和儲存單元聯絡,訪問引用時,實際上就是在訪問那個儲存單元。考慮一個引用最簡單的方法是把它當作一個奇特的指標。這個指標的優點就是不用考慮它是否初始化了,編譯器會強迫它初始化,且不用知道怎樣對它逆向引用。使用引用時有一定的規則:1)當引用被建立,必須被初始化(指標則可以在任何時候被初始化)。2)一旦一個引用被初始化為指向一個對象,它就不能被改變為對另一個對象的引用(指標則可以在任何時候指向另一個對象)。3)不可能有NULL引用。必須確保引用是和一塊合法儲存單元相關聯。
函數中最常見的引用時在函數的參數和傳回值。當被用作函數時,函數內任何對引用的更改將對函數外的參數改變。通過指標也可以這麼做,不過文法上不很清晰。如果從函數中返回一個引用,必須象從函數中返回一個指標一樣對待。在函數參數中使用常量引用特別重要。函數也許會接受臨時的對象,這個臨時對象由一個函數的傳回值或函數使用著顯式地創立,臨時對象總是不變的,因此如果不使用常量引用,參數將不被編譯器接受。C語言中如果要對指標進行引用,如果想改變指標本身而不是所指向的內容,函式宣告可能是:void f(int**),傳遞時必須取得指標的地址。而在C++中,函數參數變成指標的引用,用不著取得指標的地址。
有一種提高效率的方法是,傳值方式需要調用建構函式和解構函式,如果不想改變參數,則可以通過常量引用來傳遞,它僅需要將地址壓棧。只有一種情況不適用於傳遞地址方式,就是當傳值是唯一安全的途徑,否則將會破壞對象時(而不是修改外部對象)。
拷貝建構函式,通常被稱為X(&X)(X引用的X)。在函數調用時,這個建構函式是通過傳值方式傳遞和傳回型別的根本所在。在C和C++中,參數從右往左進棧,然後調用函數,調用代碼負責清理棧中參數,通過傳值方式傳遞參數時,編譯器簡單的將參數拷貝壓棧,並為壓棧參數產生正確拷貝。編譯器把傳回值放在寄存器中返回它。拷貝這個值得位元位等同於拷貝對象。當編譯器為函數調用產生代碼時,首先把所有參數壓棧,然後調用函數,在函數內部,產生代碼,向下移動堆棧指標為函數局部變數提供儲存單元。在組合語言call中,CPU把代碼中的函數調用指令的地址壓棧,組合語言return可以用這個地址返回到調用點。當寄存器沒有足夠大的地方儲存傳回值時,就會將傳回值的地指向一個函數參數一樣壓棧,讓函數直接將傳回值資訊拷貝到目的地。
對於傳遞和返回大的簡單結構時所用的方法是從一個地方到另一個地方拷貝位元位,對於C是可行的。但是C++中,對象比一組位元位要豐富得多。當通過傳值方式傳遞一個對象時,就創立了一個新的對象。函數體內的對象由原函數體外的原來存在的對象傳遞。從函數返回也是如此。當編譯器從現有對象建立新對象時,可以通過定義自己的函數來做些事情,因為是在建立新對象,所以這個函數應該是建構函式,並且傳遞給這個函數的單一參數是所建立的對象的來源物件,但該對象不能穿入建構函式,因為試圖定義處理傳值方式的函數按句法構造傳遞一個指標是沒有意義的,所以可以使用來源物件的引用,這個函數被稱為拷貝建構函式。當包含更複雜的類型時,如果沒有建立拷貝構在函數,C++編譯器也將自動建立拷貝建構函式。僅當準備用傳值的方式傳遞類對象時,才需要拷貝建構函式。有個簡單的方法防止通過傳值的方式傳遞:生命一個私人拷貝建構函式。甚至不用去定義,除非成員函數或友元函數需要執行傳值方式的傳遞。
一般來說引用文法比指標文法要好,當傳遞一個可以改變的參數時,從代碼維護角度來說,使用指標可能更安全。除非打算通過地址修改外部對象,不然都用const引用傳遞地址。
指標是一些指向記憶體位址的變數,既可以是資料地址,也可以是函數地址。所以可以在運行時改變指向函數的地址。除了C++的成員指標選擇的內容是在類之外,C++的成員指標遵守同樣的原則。不過由於指標需要一個地址,而類的內部沒有地址,選擇一個類的成員意味著在類中位移。只有把位移和具體對象的開始地址結合,才能得到實際地址。成員函數的文法要求選擇一個對象時同時逆向引用成員指標。為了取得類成員指標所指向的內容,必須用*號逆向引用,但由於只是對象內的位移,所以還要指定哪個對象。因此*號必須和逆向引用的對象結合使用。對於一個指向對象的指標新文法為->*,對於一個對象或引用則為.*。對於成員函數產生的成員指標,如格式:int (*fp)(float)。(*fp)的圓括弧迫使編譯器正確判斷定義,沒有則該運算式返回一個int*值的函數。