高谈阔论C++
现在谈谈指针和引用吧,这个话题经久不衰
没有空引用之说,也就是说,引用是给别人起别名,但是这个人必须存在。
但是相反,指针就没有这个要求。
这个是两个差别之一,差别往往是区分两个不同事物的地方,但是之所以差别,也可以利用这个差别来限制另一个没有这方面的功能的地方,例如,我们不想让某个对象为null,就可以设置为引用,则不可能为空
也正是引用这个性质,导致了其定义的时候必须初始化,也就是起别名的时候必须指定个人,同样指针没这个要求,也即是指针可以是个未初始化的变量。
#include <iostream>
using namespace std;
int main()
{
char *pc = 0;
char &rc = *pc;
cout << rc << endl;
return 0;
}
上面这段代码虽然可以编译通过,但是运行出现错误,这是很傻逼的写法
引用是其别名,还要求一旦起了别名,这个人死之前,不能在给别人起这个别名,不然混淆了。
也就是引用初始化之后,不能在指向其他变量。但是指针没有这个要求。
从这点不同也从一定程度上反映出了,指针可以做真正的变量,可以像变量一样使用,没有什么约束。
但是引用就不同了,它在一定程度上,更像是常量。
注意一点:是引用不能改变,并不代表它指向的内容不能改变,也即是说:
引用总是指向它最初获得的那个对象(即使这个对象以后内容改变了)
初始化以后不能改变(这方面和类中的静态变量有一定程度的异曲同工之妙)
这一点可以作为一个暗锁:如果不希望指向内容改变且指向对象不为空时使用引用,如果希望它在不同场所指向不同使用指针且有不指向任何对象的可能时使用指针
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1("Nancy");
string s2("Clancy");
string *ps = &s1;
cout << "s1 = " << s1 << "\ts2 = " << s2 << "\t*ps = " << *ps << "\tps = " << ps << endl;
ps = &s2;
cout << "s1 = " << s1 << "\ts2 = " << s2 << "\t*ps = " << *ps << "\tps = " << ps << endl;
string &rs = s1;
cout << "s1 = " << s1 << "\ts2 = " << s2 << "\trs = " << rs << "\t&rs = " << &rs << endl;
rs = s2; //rs仍代表s1,但是现在s1的值变成了“Clancy”,即s2的内容
//相当于指针的 *p = s1,只是这里的形式更容易让人产生误解,要分清楚
cout << "s1 = " << s1 << "\ts2 = " << s2 << "\trs = " << rs << "\t&rs = " << &rs << endl;
return 0;
}
代码最具有说服力,我们从上面代码中可以分析出以上结果
因为没有所谓的空引用,也就是说使用引用比指针高效,因为不用再检查它的有效性。
就像查人,同样的人数,如果确定这些人(引用)一定存在,查的肯定快
void printDouble(const double & rd)
{
cout << rd; //不需要测试rd,它一定代表某个double
}
void printDouble(const double * pd)
{
if(pd) //好的编程习惯要做此检查
cout << *pd;
}
另外,引用也有一些其他的好处和作用
最常见的是作为返回值返回引用类型,便于修改,特别是operator[] 操作符的重载
总结一下吧:引用不能改变指向,必须初始化,不能引用对象为空。能完成一些操作符重载指针完成不了的事情