天天看点

【C++研发面试笔记】4. 指针与引用

【C++研发面试笔记】4. 指针与引用

4.1 引用

引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。

引用的声明方法:类型标识符 &引用名=目标变量名。

int a; int &ra=a; //定义引用ra,它是变量a的引用,即别名

4.1.1 引用的特点

(1)&在此不是求地址运算,而是起标识作用。

(2)类型标识符是指目标变量的类型。

(3)声明引用时,必须同时对其进行初始化。

(4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。

ra=1; 等价于 a=1;

(5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与&a相等。

(6)不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。

4.1.2 引用作为参数

引用的一个重要作用就是作为函数的参数。以前的C语言中函数参数传递是值传递,如果有大块数据作为参数传递的时候,采用的方案往往是指针,因为这样可以避免将整块数据全部压栈,可以提高程序的效率。但是现在(C++中)又增加了一种同样有效率的选择(在某些特殊情况下又是必须的选择),就是引用。

void swap(int &p1, int &p2) //此处函数的形参p1, p2都是引用

{ int p; p=p1; p1=p2; p2=p; }

为在程序中调用该函数,则相应的主调函数的调用点处,直接以变量作为实参进行调用即可,而不需要实参变量有任何的特殊要求。

(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给 形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

4.1.3 常引用

常引用声明方式

:const 类型标识符 &引用名=目标变量名;

用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

4.1.4 引用作为返回值

要以引用返回函数值,则函数定义时要按以下格式:

类型标识符 &函数名(形参列表及类型说明){函数体}

(1)以引用返回函数值,定义函数时需要在函数名前加&

(2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

4.1.5 引用与操作符重载

有一些操作符必须能够连续使用,比如赋值操作符=:

x = j = 10;

或者

(x=10)=100;

。赋值操作符的返回值必须是一个左值,以便可以被继续赋值。

可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!

因此,返回一个流对象引用是惟一选择。在另外的一些操作符中,却千万不能返回引用,比如

+-*/

四则运算符。因为它们必须构造一个新对象作为返回值,只能是返回一个对象了。

4.1.6 引用和多态

引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。实现由基类调用派生类函数的效果

class  A;
class  B:public A{……};
B  b;
A  &Ref = b; // 用派生类对象初始化基类对象的引用
           

这里的Ref 只能用来访问派生类对象中从基类继承下来的成员,是基类引用指向派生类。如果A类中定义有虚函数,并且在B类中重写了这个虚函数,就可以通过Ref产生多态效果。

4.1.7 引用总结

(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。

(2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。

(3)引用与指针的区别是:指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

(4)使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

4.2 指针

4.2.1 指针与数组

int* pa[] 表示指针数组 指一个数组里面装着指针
int (*p)[]表示数组指针,表示一个指向数组的指针
*name[]代表name,是个有重指针的变量;
**p当然也是二重指针。
           

在表达式里,*或[]代表消去一重指针(取值),而&代表增加一重指针;

变量定义时,*是指针变量,[]是指针常量,二者都代表有指针存在;

由*声明的指针是指针变量,它可以随意修改指向的方向,包括用new建立一片空间然后让指针指向它;然而用[]声明的指针是指针常量(然而它指向的量却可以是一个变量),你不能修改指针常量,但是你可以借助这个指针常量去修改它所指向的指针变量。

4.2.2 函数指针变量

函数指针变量的声明方法为:

返回值类型 ( * 指针变量名) ([形参列表]);

根据定义,

int(*pf)(float);
int (*p)(float)=&f1;
pf,p都是函数指针变量。
           

函数地址:C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。函数地址的获取,可以是函数名,也可以在函数名前加取地址符&。

4.2.3 const修饰指针

指针本身是常量不可变:

(char*) const pContent;

指针所指向的内容是常量不可变:

const (char) *pContent;

(char) const *pContent;

两者都不可变:

const char* const pContent;

这篇博文是个人的学习笔记,内容许多来源于网络(包括CSDN、博客园及百度百科等),博主主要做了微不足道的整理工作。由于在做笔记的时候没有注明来源,所以如果有作者看到上述文字中有自己的原创内容,请私信本人修改或注明来源,非常感谢>_<