C++基礎——有關引用的問題

Inside_Zhang發表於2015-11-09

基本用法

我們還是從具體的程式碼出發,那種陳腐的傳值、傳指標、傳引用之間的區別不再贅述,任何一本C語言的書中都有詳細的例子:

int x = 10, y = 20;
int& refX = x;          
            // 引用必須依附物件而存在,必須與合法的記憶體單元相關聯
            // 引用(refX)是變數(x)的別名(alias)
            // 對引用(refX)的全部操作等價於對所關聯變數(x)的的操作
refX = y;   
            // 將y的值賦值給refX,也就是賦值給x
            // 而不是修改refX的指向使其指向y
            // C++不允許將reference改指向不同物件
            // refX一日指向x,就終身指向x,絕不三心二意,朝三暮四
cout << "refX = "<< refX << ", x = " << x << endl;      // 20 20

上述程式碼反映在記憶體單元中:


這裡寫圖片描述

我們繼續理解C++不允許讓reference改指向不同物件


這裡寫圖片描述

也就是怎麼修改引用的值都可以,但就是不可以修改其地址或者讓其指向另外一個物件。

int x = 10, y = 20;
int& refX = x;
&refX = &y;         // 錯誤:表示式必須是可修改的左值(left value)
int x = 10, y = 20;
int& refX = x;
int& refY = y;
refX = refY;            // 將refY所指向的y的值賦給refX,也即是賦給x
refY = 30;              // 修改y的引用refY的值,也即是修改修改y的值
cout << "refX = " << refX << ", x = " << x << endl;     // 20 20
cout << "refY = " << refY << ", y = " << y << endl;     // 30 30


這裡寫圖片描述

同理,我們可類推其他型別資料相互引用的例子:

string s1("hello"), s2("world");
string& refS1 = s1;
string& refS2 = s2;
refS1 = refS2;
refS2 = "China";
cout << "refS1 = " << refS1 << ", s1 = " << s1 << endl;
            // refS1 = "world", s1 = "world"
cout << "refS2 = " << refS2 << ", s2 = " << s2 << endl;
            // refS2 = "China", s2 = "China"

作為類的成員變數時

上一節的易混淆之處還好明白,陷阱還較容易避免。當引用作為一個類的成員函式存在且與賦值運算子(operator=)相結合的時候,就比較不容易發現問題了,我們認為地構造一個以string型別作為成員變數的類:

class Student
{
public:
    Student(string& name):_name(name){}
                    // 這裡必須以引用作為引數進行傳遞,
                    // 如果是值語義的話,
                    // 成員變數最終得到的是一個區域性物件的引用
                    // 而這個區域性物件會在建構函式退出時,被銷燬
                    // 既然引用所指向的物件都不存在了,自然
private:
    string& _name;
}

int main(int, char**)
{
    // Student stu1("zhang");    
    // 錯誤,型別不匹配,"zhang"是const char[6]

    Student stu1(string("zhang"));
    Student stu2(string("li"));
    stu1 = stu2;     
                // 錯誤,operator=不可用
                // C++不允許讓reference改指向不同的物件
    return 0;
}

解決方案之一

將成員變數從引用語義,改變為值語義

解決方案之二

重寫賦值運算子(operator=):

class Student
{
public:
    Student(string& name):_name(name){}
    Student& operator=(const Student& rhs)
    {
        _name = rhs._name;
        return *this;
    }
private:
    string& _name;
}

關於向引數型別分別為stringstring&的函式傳遞字元陣列時可能發生的型別退化等更有趣更詳盡的討論出門左轉請參閱<C++基礎——使用字串作為函式模板的實參>

相關文章