引用類型

引用類型

引用類型 由類型的實際值引用(類似於指針)表示的數據類型。如果為某個變數分配一個引用類型,則該變數將引用(或“指向”)原始值。不創建任何副本。引用類型包括類、接口、委託和裝箱值類型。

簡介

(reference type)

“引用”(reference)是c++的一種新的變數類型,是對C的一個重要補充。它的作用是為變數起一個別名。假如有一個變數a,想給它起一個別名,可以這樣寫:

int a;int &b=a;

這就表明了b是a的“引用”,即a的別名。經過這樣的聲明,使用a或b的作用相同,都代表同一變數。在上述引用中,&是“引用聲明符”,並不代表地址。

不要理解為“把a的值賦給b的地址”。引用類型的數據存儲在記憶體的堆中,而記憶體單元中只存放堆中對象的地址。聲明引用並不開闢記憶體單元,b和a都代表同一變數單元。

注意:在聲明引用變數類型時,必須同時使之初始化,即聲明它代表哪一變數。在聲明一個變數的引用之後,在本函式執行期間,該引用一直與其代表的變數相聯繫

,不能再作為其他變數的別名。下面的用法不對:

int a1,a2;

int &b=a1;

int &b=a2;//企圖使b變成a2的別名(引用)是不行的。這樣是錯誤的。

我們可以把a2的值賦給b。

b=a2;

區別

引用和指針的區別
 看實例吧:

引用是C++中的概念,初學者容易把引用和指針混淆一起。

下面的程式中,n是m的一個引用(reference),m是被引用物(referent)。

int m;

int &n = m;

n相當於m的別名(綽號),對n的任何操作就是對m的操作。

所以n既不是m的拷貝,也不是指向m的指針,其實n就是m它自己。

引用的規則

(1)引用被創建的同時必須被初始化(指針則可以在任何時候被初始化)。

(2)不能有NULL引用,引用必須與合法的存儲單元關聯(指針則可以是NULL)。

(3)一旦引用被初始化,就不能改變引用的關係(指針則可以隨時改變所指的對象)。

以下示例程式中,k被初始化為i的引用。

語句k = j並不能將k修改成為j的引用,只是把k的值改變成為6。

由於k是i的引用,所以i的值也變成了6。

int i = 5;

int j = 6;

int &k = i;

k = j; // k和i的值都變成了6;

主要功能

引用的主要功能:傳遞函式的參數和返回值。

C++語言中,函式的參數和返回值的傳遞方式有三種:值傳遞、指針傳遞和引用傳遞。

以下是"值傳遞"的示例程式。

由於Func1函式體內的x是外部變數n的一份拷貝,改變x的值不會影響n, 所以n的值仍然是0。

void Func1(int x)

{

x = x + 10;

}

...

int n = 0;

Func1(n);

cout << "n = " << n =" 0" n =" 0;" n = " << n << endl; // n = 10 以下是" size="14">

void Func3(int &x) { x = x + 10; } ... int n = 0; Func3(n); cout << "n = " << n =" 10">

(1) 在實際的程式中,引用主要被用做函式的形式參數--通常將類對象傳遞給一個函式.引用必須初始化. 但是用對象的地址初始化引用是錯誤的,我們可以定義一個指針引用。

1 int ival = 1092;

2 int &re = ival; //ok

3 int &re2 = &ival; //錯誤

4 int *pi = &ival;

5 int *π2 = pi; //ok

(2) 一旦引用已經定義,它就不能再指向其他的對象.這就是為什麼它要被初始化的原因。

(3) const引用可以用不同類型的對象初始化(只要能從一種類型轉換到另一種類型即可),也可以是不可定址的值,如文字常量。例如

double dval = 3.14159;

//下3行僅對const引用才是合法的

const int &ir = 1024;

const int &ir2 = dval;

const double &dr = dval + 1.0;

上面,同樣的初始化對於非const引用是不合法的,將導致編譯錯誤。原因有些微妙,需要適當做些解釋。

引用在內部存放的是一個對象的地址,它是該對象的別名。對於不可定址的值,如文字常量,以及不同類型的對象,編譯器為了實現引用,必須生成一個臨時對象,引用實際上指向該對象,但用戶不能訪問它。

例如:

double dval = 23;

const int &ri = dval;

編譯器將其轉換為:

int tmp = dval; // double -> int

const int &ri = tmp;

同理:上面代碼

double dval = 3.14159;

//下3行僅對const引用才是合法的

const int &ir = 1024;

const int &ir2 = dval;

const double &dr = dval + 1.0;

內部轉化為:

double dval = 3.14159;

//不可定址,文字常量

int tmp1 = 1024;

const int &ir = tmp1;

//不同類型

int tmp2 = dval;//double -> int

const int &ir2 = tmp2;

//另一種情況,不可定址

double tmp3 = dval + 1.0;

const double &dr = tmp3;

(4) 不允許非const引用指向需要臨時對象的對象或值,即,編譯器產生臨時變數的時候引用必須為const!!!!切記!!

int iv = 100;

int *πr = &iv;//錯誤,非const引用對需要臨時對象的引用

int *const πr = &iv;//ok

const int ival = 1024;

int *π_ref = &ival; //錯誤,非const引用是非法的

const int *π_ref = &ival; //錯誤,需要臨時變數,且引用的是指針,而pi_ref是一個非常量指針

const int * const π_ref = &ival; //正確

//補充

const int *p = &ival;

const int *π_ref = p; //正確

(5) ********對於const int *const & pi_ref = &iva; 具體的分析如下:*********

1.不允許非const引用指向需要臨時對象的對象或值

int a = 2;

int &ref1 = a;// OK.有過渡變數。

const int &ref2 = 2;// OK.編譯器產生臨時變數,需要const引用

2.地址值是不可定址的值

int * const &ref3 = &a; // OK;

3.於是,用const對象的地址來初始化一個指向指針的引用

const int b = 23;

const int *p = &b;

const int *& ref4 = p;

const int *const & ref5 = &b; //OK

const引用的語義到底是什麼?

最後,我們可能仍然不明白const引用的這個const的語義是什麼

const引用表示,試圖通過此引用去(間接)改變其引用的對象的值時,編譯器會報錯!

這並意味著,此引用所引用的對象也因此變成const類型了。我們仍然可以改變其指向對象的值,只是不通過引用

下面是一個簡單的例子:

1 #include<iostream>

2 using namespace std;

3

4 int main()

5 {

6 int val = 1024;

7 const int &ir = val;

8

9 val++;

10 //ir++;

11

12cout<<"val="<<val<<"\n";

13cout<<"ir="<<ir;

14return0;

15 }

其中第10行,如果我們通過ir來改變val的值,編譯時會出錯。但是我們仍然可以通過val直接改變其值(第9行)

總結:const引用只是表明,保證不會通過此引用間接的改變被引用的對象!

另外,const既可以放到類型前又可以放到類型後面,放類型後比較容易理解:

string const *t1;

const string *t1;

typedef string* pstring;string s;

const pstring cstr1 = &s;就出錯了

但是放在類型後面不會出錯:

pstring const cstr2 = &s;

使用

引用在類中的使用


 1. #include<iostream>

2. using namespace std;

3.

4. class A

5. {

6. public:

7. A(int i=3):m_i(i){}

8. void print()

9. {

10. cout<<"m_i="<<m_i<<endl;

11. }

12. private:

13. int m_i;

14. };

15.

16. class B

17. {

18. public:

19. B(){}

20. B(A& a):m_a(a){}

21. void display()

22. {

23. m_a.print();

24. }

25. private:

26. A& m_a;

27. };

28.

29.

30. int main(int argc,char** argv)

31. {

32. A a(5);

33. B b(a);

34. b.display();

35. return0;

36. }

注意

引用在類中使用需注意
其中,要注意的地方就是引用類型的成員變數的初始化問題,它不能直接在構造函數裡初始化,必須用到初始化列表,且形參也必須是引用類型。

凡是有引用類型的成員變數的類,不能有預設構造函式。原因是引用類型的成員變數必須在類構造時進行初始化。

如果兩個類要對第三個類的數據進行共享處理,可以考慮把第三個類作為這兩個類的引用類型的成員變數

相關詞條

相關搜尋

熱門詞條

聯絡我們