C++中的引用

来源:互联网 发布:凤城高中淘宝屋 编辑:程序博客网 时间:2024/06/03 14:58

C++中引用和指针的概念常常被拿来对比,二者之间有非常相似的特性。这给初学者带来了困扰,特别是很多编译器使用了指针来实现引用,更增添二者之间扑朔迷离的牵连关系!本文仅就引用的特性做简要介绍,旨在帮助读者更好地理解引用的概念和避免常见的错误!


引用的三大特性

  1. 不存在空引用
  2. 所有引用都要初始化
  3. 引用所指向的对象不可更改

仔细品味以上引用的三大特性,就会发现这三点都是相对于指针而言的。关于这三点,指针有完全相反的特性! 因此以上三点实则也是引用与指针的三大区别!读者应当仔细品之,并牢记于心,绝大多数对引用的误用都滋生与对这三大区别的误解!


引用的本质是别名

引用的三大特性,表面上看似乎是相对于指针的特性总结而来,并与之区别! 但

引用的的本质是别名

确是这三大特性的内在根源, 换句话说引用所指向的对象在赋给引用之前一定要先于引用被创建。这和使用typedef创建类型的别名有异曲同工之妙!

template< typename T1, typename T2>class MyType{   public:   MyType();   MyType( const MyType&);     void swap( T1&, T2& );};int main(){   typedef MyType<int, short> TType;   TType swapper;   int a = 10;   short b = 2;   swapper.swap( a, b );   return 0;}

引用的常见错误

double& d = 10.5; //错误double a = 10.5;double& d = a;    //正确

错误在哪里呢? 要对此有比较深入的理解涉及到左值,右值,左值引用和右值引用的概念。 为了尽快讲清楚这个问题, 我们对左值,右值的概念做一个简短的介绍。

左值是指表达式结束后依然存在的持久对象
右值对应于临时对象,表达式结束的时候已经不存在

在一个赋值表达式中,等号左边的一般就是左值,右边的一般就是右值。因此有了左值右值的叫法, 但对于左值右值的判断切不可以此作为标准,而应该以定义为准!

上述代码中 d 是一个左值引用, 而 10.5 显然是一个临时对象,因此是一个右值。问题来了,一个非常量左值引用可以绑定到一个右值对象吗? 答案是否定的, 我们可以依据C++标准得到这个答案:

C++标准规定非常量左值引用只能绑定到一个非常量左值

因此上述代码中 d = a 是正确的用法。那么标准为什么会这么规定呢? 设想一个函数:

void swap( double& d1, double& d2);...swap(10.0, 1.0);

这段代码是不能通过编译的, 因为显然他违反了上述规范。 这里的swap 函数显然将会修改它的参数,如果我们允许将临时变量作为参数输入, 那我们不能获得修改后的结果。因此输入的参数必须是已经创建好并初始化的实参,这样我们才能够获得函数修改后的结果!这里总结一下:

当一个函数的参数是一个非常量引用的时候, 程序员实际是在暗示编译器该引用所指向的对象将会被函数修改,因此调用者必须确保输入的实参是一个左值(非临时变量)。否则函数所做的修改将无法获取!为了避免由此所造成的危险和不确定性,C++ 规定在此情形下,临时变量不可赋给非常量引用。

那么对于常量左值引用可以绑定到哪些对象呢? 啊, 它简直是所向披靡,见到谁都可以绑上去!

double d = 2.1;const double  e  = 0.2;const double& d1 = d + e;const double& d2 = 1.4;const double& d3 = d;const double& d3 = e;

这些情形下他都完全没问题!因此下面这段代码是可以的:

const std::string& s = std::string("Hello ") + "World!";

那么这个呢?

std::string& s = std::string("Hello ") + "World!";
0 0
原创粉丝点击