前段时间接到个电面,被问到C++中指针与引用的差别,由于脑中对这两个概念的理解并不是很清楚,呃,应该被鄙视了吧。
咳咳,说多了都是泪。
今天想从几个方面说说它们两者的区别与联系,算是给自己个交代,也是给后来人提个醒。
----------我---是---分---割---线--------------------------------------------------------------------------------
指针和引用形式上很好区别,但是他们似乎有相同的功能,都能够直接引用对象,对其进行直接的操作。
1. 指针:对于一个类型T,T*就是指向T的指针类型,即一个T*类型的变量可以保存一个T对象的地址。
2. 引用:引用是一个对象的别名(声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元;对引用求地址就是对目标变量求地址),引用通常被用于作为“参数”,“常(const)引用”以及作为“返回值”。
2.1. 作为参数
void swap(int &v1, int &v2)
{
int v;
v = v1;
v1 = v2;
v2 = v;
}
main()
{
int a, b;
cin>>a>>b;
swap(a, b);
cout<<a<<" "<<b;
}
上述程序运行后,如果输入的数据是1 4,则输出的结果为4 1。
从上例可以看出,传递引用给函数与传递指针的效果是一样的,在被调函数中对形参变量的操作就相当于对其相应的目标对象(在主调函数中)的操作,即直接对实参操作。
2.2. 这里要着重说下常引用,因为我看到有些人的博文说引用没有const,这是不对的
常引用的声明方式:
const 类型标识符 &引用名 = 目标变量名
用这种方式申明的引用,不能通过引用对目标变量的值进行修改
int v = 0;
const int &rv = v;
rv = 1; //错误
v = 1; //正确
常量指针:指向常量的指针,在指针定义语句的类型前加const,表示指向的对象是常量。
常量指针定义"const int* pointer=&v,告诉编译器*pointer是常量,不能将*pointer作为左值进行操作。
有一个规则可以很好的区分const是修饰指针,还是修饰指针指向的数据——画一条垂直穿过指针声明的星号(*),如果const出现在线的左边,指针指向的数据为常量;如果const出现在右边,指针本身为常量。
3. 引用作为返回值
要以引用作为函数的返回值,则函数定义时要按以下格式:
类型标识符 &函数名(形参列表及类型说明)
{函数体}
引用作为返回值,必须遵守一下规则:
1) 不能返回局部变量的引用;
2) 不能返回函数内部new分配的内存的引用;
3) 可以返回类成员的引用,但最好是const;
... ...
*具体可参照Effective C++
另外,引用是除指针外另一个可以产生多态的手段。
class A;
class B : public A{......};
B b;
A &rb = b; //用派生类对象初始化基类对象的引用
**引用总结:
1) 在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。
2) 用引用传递函数的参数,能保证参数传递中不产生副本,提高传递效率,且通过const的使用,保证了引用传递的安全性。
3) 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性会变差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
4) 使用引用的时机。流操作符“<<”和“>>”、赋值操作符“=”的参数和返回值、拷贝构造函数的参数都推荐使用引用。
----------我---是---分---割---线--------------------------------------------------------------------------------------------------------------
指针和引用的区别:
1. 引用不可以为空,但指针可以为空,故定义一个引用的时候,必须初始化。
2. 引用不可以改变指向,对一个对象"从一而终",但是指针可以改变指向,而指向其它对象。
3. 引用的大小是所指向的变量的大小,因为引用只是一个别名,而指针的大小是指针本身所占内存的多少。
4. 由于不存在空引用,并且引用一旦被初始化为指向某个对象,它就不能被改变为另一个对象的引用,因此引用比指针更安全。