小记:静默如初,安之若素
C++的引用(Reference)
1. 定义
1)引用就是某个变量的别名,对引用的操作与变量操作完全相同。
2)语法
类型 & 引用名 = 变量名;
注:引用定义时必须初始化,初始化后绑定的变量不能再做修改;
注:引用的类型与初始化时绑定的变量类型一致;
eg:
int a = 123;
int &b = a;//b就是a的引用(别名),对引用初始化
b++;
cout<< a << endl;//123
int c = 321;
b = c;//将c的值赋值给b,等价赋值给a
cout << a << endl;//321
1 #include <iostream>
2 using namespace std;
3
4 int main(int argc, char * argv[])
5 {
6 int a = 10;
7 int &b = a;//b引用了a,b就是a的别名,b的内存空间与a相同
8 cout<< "&a = "<< &a <<" , a = "<< a <<endl;
9 cout<< "&b = "<< &b <<" , b = "<< b <<endl;
10
11 //对引用进行操作和对变量进行操作相同
12 b++;
13 cout<<"a = "<< a <<endl;//11
14 cout<<"b = "<< b <<endl;//11
15 a++;
16 cout<<"a = "<< a <<endl;//12
17 cout<<"b = "<< b <<endl;//12
18
19 //引用定义时必须初始化
20 //int &r;//error: ‘r’ declared as reference but not initialized
21
22 //初始化后绑定的变量不能再做修改
23 int c = 66;
24 b = c;//将c的值赋值给b(a), 而不是修改引用目标
25 cout<<"a = "<< a <<endl;//12
26 cout<<"b = "<< b <<endl;//12
27
28 //引用的类型与变量的类型一致
29 //double &d = c;//error: invalid initialization of non-const reference of
30 //type ‘double&’ from an rvalue of type ‘double’
31
32 return 0;
33 }
2. 常引用
1)定义引用时加const修饰,即为常引用,不能通过常用引用修改引用的目标。
const 类型 & 引用名 = 变量名;<=等价=> 类型 const & 引用名 = 变量名;
eg:
int a = 100;
const int *pa = &a; <=等价=> int const *pa = &a;
const int &b = a;//b就是a的常引用
b++;//error
a = 100;
cout<< b << endl;//100
- 普通的引用只能引用左值,而常引用也叫万能引用,既能引用左值也能引用右值。
eg:
int a = 0;
a = 100;//a是左值
100 = 200;//100是右值
eg:普通的引用只能引用左值
int a = 100;
int &b = a;//ok
int &b = 100;//error,
b = 200;//error,该语句表示100 = 200,
const int &b = a;//ok
const int &b = 100;//OK
3)关于左值和右值
左值:可以放到赋值运算符(=)的左侧变量(也可以放到右侧),一般普通的变量都是左值;
普通的变量;
赋值表达式;
前++,前--表示式结果
右值:只能放到赋值运算符(=)的右侧变量,一般常量都是右值;
常量;
大多数表示式结果;
函数返回临时变量(将亡右值)
3. 引用型函数参数
1)将引用用于函数的参数,这时形参就是实参的别名,可以通过形参直接修改实参的值,同时避免参数传递的过程,减小函数调用的开销。
2)引用型参数有可能意外修改实参的值,如果不希望修改实参本身,可以将形参定义为常引用,提高传参效率的同时还可以接受常量型的实参。
(1)通过形参直接修改实参的值
1 #include <iostream>
2 using namespace std;
3
4 //两个整形数用异或交换效率更高(C 语言)
5 void swap1(int *x, int *y)
6 {
7 *x = *x ^ *y;//011 ^ 101 = 110(x)
8 *y = *x ^ *y;//110 ^ 101 = 011(y)
9 *x = *x ^ *y;//110 ^ 011 = 101(x)
10 }
11
12 //两个整形数用异或交换效率更高(C++ 语言)
13 void swap2(int &x, int &y)
14 {
15 x = x ^ y;//011 ^ 101 = 110(x)
16 y = x ^ y;//110 ^ 101 = 011(y)
17 x = x ^ y;//110 ^ 011 = 101(x)
18 }
19
20
21 int main(int argc, char *argv[])
22 {
23 int a = 3, b = 5;
24 cout<<"a = "<< a <<" b = "<< b <<std::endl;
25 //swap1(&a, &b);
26 swap2(a, b);
27 cout<<"a = "<< a <<" b = "<< b <<std::endl;
28 return 0;
29 }
(2)提高传参的效率
1 #include <iostream>
2 using namespace std;
3
4 struct Student{
5 char name[128];
6 int age;
7 };
8
9 void print(const Student& s)
10 {
11 cout<< s.name << "," << s.age/*++*/ << endl;
12 }
13
14 int main(int argc, char *argv[])
15 {
16 const Student stu = {"zhang", 28};
17 print(stu);
19 return 0;
20 }
4. 引用型函数返回值
1)可以将函数的返回值声明为引用,避免返回值所带来的内存开销;
2)如果一个函数返回类型被声明为普通引用,那么该函数返回值是一个左值;
3)如果不希望函数直接返回左值,可以返回常引用;
注:不要从函数中返回局部变量的引用,因为所引用的变量内存会在函数返回以后被释放,但是可以返回成员变量,静态变量以及全局变量的引用
eg:
int func(void)
{
static int a = 100;
return a;//int tmp = a;实际返回结果是tmp
}
-----------------------
int &func(void)
{
static int a = 100;
return a; //没有tmp, 实际返回的就是a的自身
}
func() = 200;//ok:
--------------------------------------
const int &func(void)
{
static int a = 100;
return a; //没有tmp, 实际返回的就是a的自身
}
func() = 200;//error
//笔试题:指针和引用的区别
5. 引用和指针
1)如果从C角度去看引用,其本质就是指针,但是在C++中建议使用引用而不是指针;
eg:
int a = 100;
int &ra = a;
int *const pa = &a;
*pa <==> ra
2)指针可以不做初始化,其目标可以随意改变(指针常量除外);而引用必须初始化,而且引用的目标不能再改变。
eg:
int a = 100, b = 200;
//指针
int *p;//ok,指针可以不做初始化
p = &a;//p指向a
p = &b;//p指向a
----------------------
//引用
int &r;//error
int &r = a;//引用必须定义初始化
r = b;//ok,但是该过程是赋值操作,不能改变引用的目标
//了解
3)定义指针的时候可以定义指针的指针(二级指针),但是不能定义引用的指针。
eg:
int a = 100;
int *p = &a;
int **pp = &p;//二级指针
-----------------------------
int &r = a;
int &*pr = &r;//error
4)可以定义指针的引用(指针别名),但是不能定义引用的引用。
eg:
int a = 100;
int *p = &a;
int *& rp = p;//ok,指针的引用,给指针变量起的别名
-----------------------------
int &r = a;
int &&rr = r;//error
int &rr = r;//ok.不能叫引用的引用,就是一个普通的引用,等于给a起了另一个别名。
5)可以定义指针数组,但是不能定义引用数组。
```cpp
eg:
int a = 10, b = 20, c = 30;
int *parr[3] = {&a, &b, &c};//ok. 指针数组
int &parr[3] = {a, b, c};//error
6)可以定义数组引用(给数组起别名)
eg:
int arr[3] = {10, 20, 30};
int (&rarr)[3] = arr;//ok, arr 的别名
7)和函数指针类似,也可以定义函数的引用(给函数起别名),其语法规则和函数类似
eg:
void func(int a, int b){...}
int main(void)
{
void (*pfunc)(int, int) = func;//函数指针
pfunc(10, 20);
----------------------------
void (&rfunc)(int, int) = func;//函数引用
rfunc(10, 20);
}
注:需要与C中的typedef进行区分,typedef是指对类型进行起别名,引用就是某个变量的别名。