《c++入門經典》筆記12

第12章 建立引用

12.1什麼是引用

引用是一個別名。建立引用時,使用另外一個對象(目標)的名稱來初始化它,今後之後該引用就像是目標的另外一個名稱,對引用執行的任何操做實際上針對的就是目標。ios

有些書上說引用就是指針,這不正確。雖然引用經常是使用指針實現的,可是隻有編譯器開發人員關心這一點,做爲程序員,必須區分這兩種概念。c++

指針是存儲另外一個對象的地址的變量,而引用時對象的別名。程序員

12.2建立引用

要建立引用,須要指定目標對象的類型、引用運算符(&)和引用名。函數

程序清單12.1 Reference.cpp指針

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;

    rSomeRef = 7;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;
    return 0;
}

12.3將地址運算符用於引用

若是請求返回引用的地址,就將返回它指向的目標的地址。這是引用的特徵:他們是目標的別名code

程序清單12.2 Reference2.cpp對象

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;

    std::cout << "&intOne: " << &intOne << std::endl;
    std::cout << "&rSomeRef: " << &rSomeRef << std::endl;
    return 0;
}

一般,使用引用時,不將地址運算符用於它,而像使用目標變量那樣使用引用。blog

程序清單12.3 Assignment.cpp接口

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne:\t" << intOne << std::endl;
    std::cout << "rSomeRef:\t" << rSomeRef << std::endl;
    std::cout << "&intOne:\t" << &intOne << std::endl;
    std::cout << "&rSomeRef:\t" << &rSomeRef << std::endl;

    int intTwo = 8;
    rSomeRef = intTwo;
    std::cout << "\nintOne:\t" << intOne << std::endl;
    std::cout << "intTwo:\t" << intTwo << std::endl;
    std::cout << "rSomeRef:\t" << rSomeRef << std::endl;
    std::cout << "&intOne:\t" << &intOne << std::endl;
    std::cout << "&intTwo:\t" << &intTwo << std::endl;
    std::cout << "&rSomeRef:\t" << &rSomeRef << std::endl;
    return 0;
}

12.4可引用的目標

由於對象也是一種變量,因此可引用任何對象,包括用戶定義的對象。能夠像使用對象那樣使用對象的引用:訪問成員數據和成員函數時,使用類成員訪問運算符(.)與內置類型的引用同樣,指向對象的引用也是對象的別名。ci

12.5空指針和空引用

指針未初始化或被刪除時,應將其賦爲nullptr,但引用不同,引用不能爲空,讓引用指向空對象的程序是非法的。

12.6按引用傳遞函數參數

前面知道了函數的兩個侷限性:參數按值傳遞;return語句只能返回一個值。

經過將值按引用傳遞給函數,可消除這兩種侷限性。在c++中,按引用傳遞時經過兩種方式完成的:使用指針和使用引用。他們的語法不一樣,但效果相同:不是在函數做用域內建立備份(也就是否是值拷貝),而是將原始對象傳遞給函數。

程序清單12.4 ValuePasser.cpp

#include <iostream>
void swap(int x, int y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(x, y);
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int x, int y)
{
    int temp;
    std::cout << "Swap. Before swap,x: " << x << " y: " << y << std::endl;
    temp = x;
    x = y;
    y = temp;
    std::cout << "Swap. After swap,x: " << x << " y: " << y << std::endl;
}

main()中的值都沒變,可見值拷貝並不能改變原參的值

使用指針實現swap()

程序清單12.5 PointerSwap.cpp

#include <iostream>
void swap(int *x, int *y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(&x, &y);//將地址做爲參數傳遞
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int *px, int *py)//參數聲明爲指針
{
    int temp;
    std::cout << "Swap. Before swap,*px: " << *px << " *py: " << *py << std::endl;
    temp = *px;
    *px = *py;
    *py = temp;
    std::cout << "Swap. After swap,*px: " << *px << " *py: " << *py << std::endl;
}

使用引用實現swap()

c++的目標之一時,避免函數的調用者操心函數的工做原理,而將注意力放在函數的功能和返回值上。傳遞指針將負擔轉嫁給了調用方,而這種負擔本來不該該由調用方來承擔:調用方必須知道將要交換的對象的地址傳入。

明白引用語法的負擔應由函數的實現方承擔。爲此,可以使用引用。

程序清單12.6 ReferenceSwap.cpp

#include <iostream>
void swap(int &x, int &y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(x, y);
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int &rx, int &ry)//參數聲明爲引用
{
    int temp;
    std::cout << "Swap. Before swap,rx: " << rx << " ry: " << ry << std::endl;
    temp = rx;
    rx = ry;
    ry = temp;
    std::cout << "Swap. After swap,rx: " << rx << " ry: " << ry << std::endl;
}

可見兩種方式(指針傳地址、引用傳原參)達到的效果是同樣的,可是引用傳遞中,調用方只需傳遞變量,且在函數內部,須要使用的特殊符號減小了,下降了程序的複雜性。引用將常規變量方便而易於使用的特色和指針的強大融爲一體。

12.7理解函數頭和原型

函數原型的另外一個重要用途:經過查看原型中聲明的參數(函數原型一般放在頭文件中),程序員知道swap()的參數是按指針仍是引用傳遞的,從而將正確調用他們。

在c++中,類的使用者(其餘類中使用該類的函數)依賴於頭文件來獲悉須要的全部信息。頭文件至關於類或函數的接口,而實際實現對使用者是隱藏的。這讓程序員可以將主要精力放在要解決的問題上,而使用類或函數時無需關心它是如何實現的。

12.8返回多個值

(哦,這說和沒說是同樣的,仍是隻能return一個東西)

一種解決辦法是將多個對象按引用傳入函數,而後在函數中將正確的值賦給這些對象。因爲按引用傳遞讓函數可以修改原始對象,所以這至關於讓函數可以返回多項信息。這種函數未使用函數的返回值,可將其(指返回值)用於報告錯誤。

另外一種辦法是使用指針或引用來實現。

程序清單12.7 ReturnPointer.cpp

#include <iostream>

short factor(int, int *, int *);

int main()
{
    int number, squared, cubed;
    short error;
    std::cout << "Enter a number(0 - 20): ";
    std::cin >> number;

    error = factor(number, &squared, &cubed);

    if (!error)
    {
        std::cout << "number: " << number << "\n";
        std::cout << "square: " << squared << "\n";
        std::cout << "cubed: " << cubed << "\n";
    }
    else
        std::cout << "Error encountered!!\n";
    return 0;
}

short factor(int n, int *pSquared, int *pCubed)
{
    short vaule = 0;
    if (n > 20)
    {
        vaule = 1;
    }
    else
    {
        *pSquared = n * n;
        *pCubed = n * n * n;
        vaule = 0;
    }
    return vaule;
}

按引用返回值

雖然程序ReturnPointer.cpp可行,可是若是使用引用而不是指針,將更容易理解和維護。

程序清單12.8 ReturnReference.cpp

#include <iostream>

enum ERR_CODE//枚舉
{
    SUCCESS,
    ERROR
};

ERR_CODE factor(int, int &, int &);

int main()
{
    int number, squared, cubed;
    ERR_CODE result;

    std::cout << "Enter a number(0 - 20): ";
    std::cin >> number;

    result = factor(number, squared, cubed);

    if (result == SUCCESS)
    {
        std::cout << "number: " << number << "\n";
        std::cout << "square: " << squared << "\n";
        std::cout << "cubed: " << cubed << "\n";
    }
    else
        std::cout << "Error encountered!!\n";
    return 0;
}

ERR_CODE factor(int n, int &pSquared, int &pCubed)
{
    short vaule = 0;
    if (n > 20)
    {
        return ERROR;
    }
    else
    {
        pSquared = n * n;
        pCubed = n * n * n;
        return SUCCESS;
    }
}

相關文章
相關標籤/搜索