一、引用是现有对象的别名。用对象来初始化引用之后,那么对象的名字或引用的名字都可以用于指向该对象。
int a = 12;
int &ra = a; //ra是a的别名
--ra; //a == 11;
a = 10; //ra == 10;
int *ip = &ra; //ip指向a (C++编译器经常使用指针的方式实现引用)
二、指针和引用的三大区别:
1、不存在空引用。
2、所有引用都要初始化。(意味着当一个引用初始化时它所指向的按个对象必须存在)
3、一个引用永远指向用来对它初始化的那个对象。
三、一些编译器可以捕捉到那些明显的创建空引用的尝试:
Employee &anEmployee = *static_cast<Employee* >(0); //错误!
重复一遍:一个引用就是在该引用被初始化之前已经存在的一个对象的别名。一旦一个引用被初始化去指向一个特定的对象,那么该引用以后就不可以再指向别的对象;在一个引用的整个生命期内,该引用被绑定到用于初始化它的那个对象上。这个“别名”属性使得引用常常成为函数形参的优秀选择。如:
template <typename T>
void swap(T &a, T &b)
{
T temp(a);
a = b;
b = temp;
}
//.....
int x = 1, y = 2;
swap(x, y); //x == 2, y ==1;
四、考虑一下如下函数,它用于设置二维数组中的一个特定元素:
1、inline void set_2d( float *a, int m, int i, int j)
{
a[ i * m + j ] = a[ i * m + j ] * a[ i * m + j ] + a[i * m + j ];
}
可以将函数定义体部分换成引用版本:
float &r = a[ i * m + j ];
r = r * r + r;
2、一个指向非常量的引用是不可以用字面值或临时值进行初始化的:
double &d = 12.3; //错误
swap( std::string("Hello"), std::string(", World") ); //错误
然而,一个指向常量的引用就可以:
const double &cd = 12.3 ; //ok
template<typename T>
T add( const &a, const T &b)
{
return a + b;
}
//.....
const = std::string &greeting = add( std::string("Hello"), std::string(", World") ); //ok
当一个指向常量的引用采用一个字面值来初始化时,该引用实际上被设置为指向“采用该字面值初始化”的一个临时位置。因此,cd并非真的指向字面值12.3,而是指向一个采用12.3初始化的、类型为double的临时变量。
greeting引用则指向对add的调用所返回的无名临时string值。
一般来说,这类临时对象在创建它们的表达式的末尾被销毁(确切地说就是离开作用域并且析构函数被调用)。
然而,当这类临时对象用于初始化一个指向常量的引用时,在引用指向它们期间,这些临时对象会一直存在。