c++引用(reference)


1. 引用基本用法

引用是c++對c的重要擴充。c/c++中指針的作用基本都是一樣的,但是c++增加了另外一種給函數傳遞地址的途徑,這就是按引用傳遞(pass-by-reference),它也存在於其他一些編程語言中,並不是c++的發明。

 

變量名實質上是一段連續內存空間的別名,是一個標號(門牌號)

程序中通過變量來申請並命名內存空間

通過變量的名字可以使用存儲空間

 

對一段連續的內存空間只能取一個別名嗎?

c++中新增了引用的概念,引用可以作為一個已定義變量的別名。

基本語法:

Type& ref = val;

注意事項:

&在此不是求地址運算,而是起標識作用。

類型標識符是指目標變量的類型

必須在聲明引用變量時進行初始化。

引用初始化之后不能改變。

不能有NULL引用。必須確保引用是和一塊合法的存儲單元關聯。

可以建立對數組的引用。

//1. 認識引用
void test01(){

    int a = 10;
    //給變量a取一個別名b
    int& b = a;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //操作b就相當於操作a本身
    b = 100;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //一個變量可以有n個別名
    int& c = a;
    c = 200;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "c:" << c << endl;
    cout << "------------" << endl;
    //a,b,c的地址都是相同的
    cout << "a:" << &a << endl;
    cout << "b:" << &b << endl;
    cout << "c:" << &c << endl;
}
//2. 使用引用注意事項
void test02(){
    //1) 引用必須初始化
    //int& ref; //報錯:必須初始化引用
    //2) 引用一旦初始化,不能改變引用
    int a = 10;
    int b = 20;
    int& ref = a;
    ref = b; //不能改變引用
    //3) 不能對數組建立引用
    int arr[10];
    //int& ref3[10] = arr;
}

    //1. 建立數組引用方法一
    typedef int ArrRef[10];
    int arr[10];
    ArrRef& aRef = arr;
    for (int i = 0; i < 10;i ++){
        aRef[i] = i+1;
    }
    for (int i = 0; i < 10;i++){
        cout << arr[i] << " ";
    }
    cout << endl;
    //2. 建立數組引用方法二
    int(&f)[10] = arr;
    for (int i = 0; i < 10; i++){
        f[i] = i+10;
    }
    for (int i = 0; i < 10; i++){
        cout << arr[i] << " ";
    }
    cout << endl;

 

 

2. 函數中的引用

 

最常見看見引用的地方是在函數參數和返回值中。當引用被用作函數參數的時,在函數內對任何引用的修改,將對還函數外的參數產生改變。當然,可以通過傳遞一個指針來做相同的事情,但引用具有更清晰的語法。

如果從函數中返回一個引用,必須像從函數中返回一個指針一樣對待。當函數返回值時,引用關聯的內存一定要存在。

//值傳遞
void ValueSwap(int m,int n){
    int temp = m;
    m = n;
    n = temp;
}
//地址傳遞
void PointerSwap(int* m,int* n){
    int temp = *m;
    *m = *n;
    *n = temp;
}
//引用傳遞
void ReferenceSwap(int& m,int& n){
    int temp = m;
    m = n;
    n = temp;
}
void test(){
    int a = 10;
    int b = 20;
    //值傳遞
    ValueSwap(a, b);
    cout << "a:" << a << " b:" << b << endl;
    //地址傳遞
    PointerSwap(&a, &b);
    cout << "a:" << a << " b:" << b << endl;
    //引用傳遞
    ReferenceSwap(a, b);
    cout << "a:" << a << " b:" << b << endl;
}

 

通過引用參數產生的效果同按地址傳遞是一樣的。引用的語法更清楚簡單:

1) 函數調用時傳遞的實參不必加“&”符

2) 在被調函數中不必在參數前加“*”符

引用作為其它變量的別名而存在,因此在一些場合可以代替指針。C++主張用引用傳遞取代地址傳遞的方式,因為引用語法容易且不易出錯。

 

不能返回局部變量的引用。

函數當左值,必須返回引用。

//返回局部變量引用
int& TestFun01(){
    int a = 10; //局部變量
    return a;
}
//返回靜態變量引用
int& TestFunc02(){    
    static int a = 20;
    cout << "static int a : " << a << endl;
    return a;
}
int main(){
    //不能返回局部變量的引用
    int& ret01 = TestFun01();
    //如果函數做左值,那么必須返回引用
    TestFunc02();
    TestFunc02() = 100;
    TestFunc02();

    return EXIT_SUCCESS;
}

 

3. 引用的本質

 

引用的本質在c++內部實現是一個指針常量.

Type& ref = val; // Type* const ref = &val;

 

c++編譯器在編譯過程中使用常指針作為引用的內部實現,因此引用所占用的空間大小與指針相同,只是這個過程是編譯器內部實現,用戶不可見。

//發現是引用,轉換為 int* const ref = &a;
void testFunc(int& ref){
    ref = 100; // ref是引用,轉換為*ref = 100
}
int main(){
    int a = 10;
    int& aRef = a; //自動轉換為 int* const aRef = &a;這也能說明引用為什么必須初始化
    aRef = 20; //內部發現aRef是引用,自動幫我們轉換為: *aRef = 20;
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
    testFunc(a);
    return EXIT_SUCCESS;
}

 

4. 指針引用

 

c語言中如果想改變一個指針的指向而不是它所指向的內容,函數聲明可能這樣:

void fun(int**);

給指針變量取一個別名。

Type* pointer = NULL;  

Type*& = pointer;

Type* pointer = NULL;  Type*& = pointer;

struct Teacher{
    int mAge;
};
//指針間接修改teacher的年齡
void AllocateAndInitByPointer(Teacher** teacher){
    *teacher = (Teacher*)malloc(sizeof(Teacher));
    (*teacher)->mAge = 200;  
}
//引用修改teacher年齡
void AllocateAndInitByReference(Teacher*& teacher){
    teacher->mAge = 300;
}
void test(){
    //創建Teacher
    Teacher* teacher = NULL;
    //指針間接賦值
    AllocateAndInitByPointer(&teacher);
    cout << "AllocateAndInitByPointer:" << teacher->mAge << endl;
    //引用賦值,將teacher本身傳到ChangeAgeByReference函數中
    AllocateAndInitByReference(teacher);
    cout << "AllocateAndInitByReference:" << teacher->mAge << endl;
    free(teacher);
}

 

對於c++中的定義那個,語法清晰多了。函數參數變成指針的引用,用不着取得指針的地址。

5. 常量引用

 

常量引用的定義格式:

const Type& ref = val;

 

常量引用注意:

1.字面量不能賦給引用,但是可以賦給const引用

2.const修飾的引用,不能修改。

 

void test01(){
    int a = 100;
    const int& aRef = a; //此時aRef就是a
    //aRef = 200; 不能通過aRef的值
    a = 100; //OK
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
}
void test02(){
    //不能把一個字面量賦給引用
    //int& ref = 100;
    //但是可以把一個字面量賦給常引用
    const int& ref = 100; //int temp = 200; const int& ret = temp;
}

 

 [const引用使用場景]

    常量引用主要用在函數的形參,尤其是類的拷貝/復制構造函數。

將函數的形參定義為常量引用的好處:

  • 引用不產生新的變量,減少形參與實參傳遞時的開銷。
  • 由於引用可能導致實參隨形參改變而改變,將其定義為常量引用可以消除這種副作用。

    如果希望實參隨着形參的改變而改變,那么使用一般的引用,如果不希望實參隨着形參改變,那么使用常引用。

 

//const int& param防止函數中意外修改數據
void ShowVal(const int& param){
    cout << "param:" << param << endl;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM