引用:引用不是定义一个新的变量,而是给一个已经定义的变量重新起一个别名。
引用格式:类型&引用变量名=已定义过的变量名;
引用特点:
1. 一个变量可取多个别名
2. 引用必须初始化
3. 引用只能在初始化的时候引用一次,不能改变为再引用其他的变量。
int a = 1;
int& b = a;
cout << "a->" << a << endl;
cout << "b->" << b << endl;
cout << "a:address->" << &a << endl;
cout << "b:address->" << &b << endl;
a = 2;
cout << "a->" << a << endl;
b = 3;
cout << "a->" << b << endl;
int& c = b; // 引用一个引用变量,别名的别名
c = 4;
cout << "c->" << c << endl;
cout << "d:address->" << &c << endl;
在产生临时变量时,需加上修饰符const: 临时变量具有常性
int d1 = 4;
const int & d2 = d1;
d1 = 5; // d1改变 d2的值也会改变。
//d2 = 6; // 不能给常量(不能被修改的量)赋值
const int d3 = 1;
const int & d4 = d3;
//int&d5 = d3;
const int & d6 = 5; // 常量具有常性,只有常引用可以引用常量
double d7 = 1.1;
//int& d8 = d7; //d7是double类型,d8是int,d7赋值给 d8时要生成一个临时变量
// 也就是说d8引用的是这个带有常性的临时变量,所以不能赋值。
const int& d9 = d7; // 常量具有常性,只有常引用可以引用常量
int d =10;
float e = d; //隐式类型转换,创建了临时变量
const float &f = d; // f不是d的别名,而是进行隐转时的临时变量的别名
引用的作用:
1.作传参当不希望函数内改变参数的值时,尽量使用常引用传参。
void Swap(int& a, int& b) //传引用 形参成为实参的别名
{
int tmp = a;
b = a;
a = tmp;
}
void Swap2(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
2.做返回值
不要返回一个临时变量的引用,
若返回变量依然存在(静态,全局),尽量使用引用,减少空间的拷贝,提高效率
int& Add (int d1, int d2)
// int Add ( int d1 , int d2)
{
int ret = d1 + d2;
return ret ;
}
void ()
{
int a = 3, b = 4;
int c = Add( a, b );
cout<<"c:" <<c<< endl;
}
引用的原理:
语法:引用是别名,不会开辟出空间
底层:存地址,利用地址(指针)
指针和引用:
1. 引用只能在定义时初始化一次,之后不能改变指向其它变量(从一而终);指针变量的值可变。
2. 引用必须指向有效的变量,指针可以为空。
3. sizeof指针对象和引用对象的意义不一样。sizeof引用得到的是所指向的变量的大小,而sizeof指针是对象地址的大小。
4. 指针和引用自增(++)自减(--)意义不一样。指针加一改变指针指向,引用加一改变变量值。
5. 相对而言,引用比指针更安全。
6. 指针是一个实体,而引用仅是个别名;
7.引用使用时无需解引用(*),指针需要解引用;
8.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。
相同点:
两者都是地址的概念,指针指向一块儿内存,其内容为所指内存的地址;引用是某块儿内存的别名。
引用不是绝对安全:
void Swap (int&l, int&r)
{
int temp = l; //在此处程序崩溃,对空指针解引用
l = r;
r = temp;
}
void Test()
{
int* p = 0;
int&a = *p;//此处并不进行解引用,a只是进行取了别名,p的地址给了临时变量,a是临时变量的别名
int b = 2;
Swap (a, b);
}
指针引用和传值的效率探究: