赞
踩
引用不是新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间。
格式:引用类型& 引用变量名(对象名) = 引用实体;
注意: 引用类型和引用实体是同种类型的。
引用示例:
void Swap(int& num1, int& num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}
前言:传值返回
传引用返回
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
示例输出结果:
说明:对于以出了作用域即被销毁的变量作为返回值的,如果使用传引用返回实际上是无意义的,因为局部变量的空间已被销毁,不再属于该变量,再通过传引用返回的别名去访问该空间时,其值是不确定的,无法确保得到的还是正确结果。
注意:如果函数返回时,出了函数作用域,如果返回对象还在(空间还没还给系统,如:静态变量、全局变量、上一层栈帧中的变量、malloc开辟的等等),则可以使用引用返回,否则,必须使用传值返回。
#define N 10 typedef struct Array { int a[N]; int size; }AY; //查找数组中某个下标位置的元素 int& PosAt(AY& ay, int i) { assert(i < N);//保证不越界 return ay.a[i]; } int main() { AY ay; for (int i = 0; i < N; i++) { PosAt(ay, i) = i * 10;//用返回的别名进行修改 } for (int i = 0; i < N; i++) { cout << PosAt(ay, i) << " "; } cout << endl; return 0; }
示例输出结果:
指针和引用,在赋值和初始化时,权限可以保持或缩小,但不能放大。
示例代码:
//传值返回 int Count() { int n = 0; n++; return n; } void TestConstRef() { //示例1 const int a = 10;//const修饰的变量,具有常属性,不可修改 //错误语法,权限被放大。ra引用与a共用一块空间,而a具有常属性, //如果ra引用不具有常属性,则修改ra的值时则违背了a的常属性 //int& ra = a;//编译时会报错 const int& ra = a;//正确语法 //示例2 //int& b = 10;//错误语法,10为常量,引用权限放大 const int& b = 10;//正确语法,使引用变量b也具有常属性 //示例3 //Count函数是传值返回的,返回的是临时变量,临时变量具有常属性 //int& ret = Count();//编译报错 const int& ret = Count();//正确语法,ret为返回的临时变量的常引用 int ret2 = Count();//正确语法,将返回的临时变量赋值给ret2 //示例4 double d = 3.14; //int& rd = d;//编译报错,引用类型与引用实体不是同一种类型 //解释: //在进行类型转换(无论是强制类型转换还是自动类型提升)时都会产生临时变量 //如有int i = 0; (double)i:其并不是直接将int型变量i转换为double型, //而是通过一个临时变量将i转化为double,如果是double d = i;则是再将临时变量赋值给d //下句代码则表示rd为double型变量d强制转换为int型变量时产生的 临时变量 的常引用 //但注意,rd本质上并不是d的引用,二者也不是共用一个空间 //d仍是double型变量,rd则为int型 const int& rd = d;//编译通过 printf("d = %f\nrd = %d\nd的地址为:%p\nrd的地址为:%p\n", d, rd, &d, &rd); } int main() { TestConstRef(); return 0; }
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低了。
下面用两段测试代码来比较传值与传引用的效率:
测试代码:
#include <iostream> using namespace std; #include <time.h> struct A { int a[100000]; }; void TestFunc1(A a) {} void TestFunc2(A& a) {} void TestRefAndValue() { A a; // 以值作为函数参数 size_t begin1 = clock(); for (size_t i = 0; i < 100000; ++i) TestFunc1(a); size_t end1 = clock(); // 以引用作为函数参数 size_t begin2 = clock(); for (size_t i = 0; i < 100000; ++i) TestFunc2(a); size_t end2 = clock(); // 分别计算两个函数运行结束后的时间 cout << "TestFunc1(A)-time:" << end1 - begin1 << endl; cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl; } int main() { TestRefAndValue(); return 0; }
测试结果:
分析:从测试结果来看,值作为参数的函数运行时间要比引用作为参数的函数运行时间多得多,以引用作为参数能很好提升程序运行效率。
测试代码:
#include <iostream> using namespace std; #include <time.h> struct A { int a[10000]; }; A a; // 值返回 A TestFunc1() { return a; } // 引用返回 A& TestFunc2() { return a; } void TestReturnByRefOrValue() { // 以值作为函数的返回值类型 size_t begin1 = clock(); for (size_t i = 0; i < 1000000; ++i) TestFunc1(); size_t end1 = clock(); // 以引用作为函数的返回值类型 size_t begin2 = clock(); for (size_t i = 0; i < 1000000; ++i) TestFunc2(); size_t end2 = clock(); // 计算两个函数运算完成之后的时间 cout << "TestFunc1 time:" << end1 - begin1 << endl; cout << "TestFunc2 time:" << end2 - begin2 << endl; } int main() { TestReturnByRefOrValue(); return 0; }
测试结果:
分析:从测试结果来看,值作为返回值类型的函数运行时间要比引用作为返回值类型的函数运行时间多得多,以引用作为返回值类型能很好提升程序运行效率。
语法概念上
引用就是一个别名,没有独立空间,和其引用实体共用一块空间。而指针是有开辟独立空间的,空间中存放的是指向的变量的空间地址。int main()
{
int a = 10;
int& ra = a;//引用a
int* pa = &a;//指向a
cout << "&a = " << &a << endl;
cout << "&ra = " << &ra << endl;
cout << "&pa = " << &pa << endl;
return 0;
}
示例输出结果:
底层实现上
实际是有空间的,因为引用是按照指针方式来实现的。int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。