引用的作用

jakcerw

jakcerw

2016-01-29 12:27

引用的作用,引用的作用

引用的作用

作者: panic
2005年3月27日

  众所周知,引用作为函数参数可以避免参数对象的额外拷贝,对于非内置类型,一般而言可以获得更高的效率,同时比指针更安全,语义也更清晰。但是除此之外引用有什么特别的作用呢?在同一个作用域的引用,就像这样:

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/cyuyanjiaocheng/)
void f(){ int i = 0; int &ri = i; //这里。 //...}

  事实上,在f的内部,需要操作i的地方,完全可以直接使用i,而不必要使用ri间接操作,使用i在语义上更明确。而混合使用i和ri反倒容易引起逻辑的混乱。

似乎这是一个鸡肋,但是其实不是。

这里引用乾坤一笑文章中的例子:
例一、用C宏,书写代码更简洁
这段代码写网络程序的朋友都很眼熟,是Net/3中mbuf的实现。

struct mbuf{ struct m_hdr mhdr; union {  struct  { struct pkthdr MH_pkthdr; /* M_PKTHDR set */ union  {  struct m_ext MH_ext; /* M_EXT set */  char MH_databuf[MHLEN]; } MH_dat;} MH;char M_databuf[MLEN]; /* !M_PKTHER, !M_EXT*/} M_dat;};

  上面的代码,假如我想访问最里层的MH_databuf,那么我必须写M_dat.MH.MH_dat.MH_databuf; 这是不是很长,很难写呀?这样的代码阅读起来也不明了。其实,对于MH_pkthdr、MH_ext、MH_databuf来说,虽然不是在一个结构层次上,但是如果我们站在mbuf之外来看,它们都是mbuf的属性,完全可以压扁到一个平面上去看。所以,源码中有这么一组宏:

#define m_next m_hdr.mh_next#define m_len m_hdr.mh_len#define m_data m_hdr.mh_data... ...#define m_pkthdr M_dat.MH.MH_pkthdr#define m_pktdat M_dat.MH.MH_dat.MH_databuf... ...

这样写起代码来,是不是很精练呢!

  这里用宏很巧妙的解决了访问深层数据的问题,但是宏的固有缺点也被引入了代码中,同时,如果其他地方无意中引用了这个宏定义的头文件,而且恰好使用了名为m_pktdat的数据成员,那这个宏带来的后果可就不是我们想要的了。
  事实上用引用也可以达到类似的效果,不过必须是在使用的时候。由于引用不是标准C的组成部分,所以这只是一个C++技巧。

//假如代码是这样的:mbuf m; //这里的mbuf就是前面的struct mbuf。//如果要使用MH_ext成员,可以这样:m_ext &MH_ext = m.M_dat.MH.MH_dat.MH_ext;//然后你的代码中就可以直接使用MH_ext作为m.M_dat.MH.MH_dat.MH_ext的替代品了。

  也许看起来不是很自然,不过这无疑是一种很直接的方法。你还可以通过一个const引用来在逻辑上避免无意的写操作。
  实际的“面向对象”的C++代码中,不推荐直接数据成员的访问,取而代之的是使用Get()和Set()方法存取数据,有些人只使用Get,通过返回一个成员的引用来达到读写数据成员的双重目的,这时候,你可以在外部定义一个引用接受函数的返回,从而避免每次都要写(XXX.Get()).Get()这种拖沓的语句来访问一个深层的成员。
  引用的另一个作用,就是“别名”。别名是引用的另一种翻译,很明确的表达了引用的另一个作用。仅仅是为了代码的可读性:

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/cyuyanjiaocheng/)
//下面的代码int i = 0,j = 0;//...for( i = 0; i < 10; i++)for( j = 0; j < 10; j++ )a[i][j] = 0;//你能明白这段代码的含义嘛?有点困难,i和j的含义是不明确的,无法一眼看透。//假如改成这样:const int width = 10;const int height = 10;//...int i = 0,j = 0;//...int &line = i;int &row = j;for(line = 0;line < height;line++)for(row = 0;row < width;row++)a[line][row] = 0;//是不是好了一点?
  这并不是一个典型的例子,因为i和j的定义是任意的,某些情况你必须使用别人给定的名称很郁闷的变量,而他们又必须用来表达截然不同的含义,这时候一个引用往往可以让你清爽很多。

再看下面这个例子:
class CA{int m_i;public:int &i;int const &c_i;CA():i(m_i),c_i(m_i){};};

  这是一个简单的类,与所谓的“面向对象”的方法不同,这里使用引用实现内部数据的公用接口。这个手法用来对应 乾坤一笑 的另一段话:
  这就是偶说的PME模型的问题了,delphi、java、c#之类的语言都提供一种叫做属性的语法,大概是这个样子的:

class A{property int x{get {return x;}set {x = value;}}};A a;
这样, 就可以这么访问了 a.x = 8; int b = a.x;

这比用 a.setx(8); b=a.getx();直观多了。

  你可以用 CA a; a.i访问CA的私有数据成员,达到像属性方法那样的效果。但是这个方法在VC6下的表现却不尽如人意,因为它存储了一个指针用来取代语法上的引用,这导致类体积不必要的扩张,是我们所不希望看到的。也许在实现
展开更多 50%)
分享

猜你喜欢

引用的作用

C语言教程 C语言函数
引用的作用

php的变量引用 函数引用 对象引用

PHP
php的变量引用 函数引用 对象引用

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

Excel更改引用方式在绝对引用与相对引用之间快速切换

软件教程 电脑应用 excel
Excel更改引用方式在绝对引用与相对引用之间快速切换

JavaScript引用对象的途径

Web开发
JavaScript引用对象的途径

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

javascript引用对象的方法

Web开发
javascript引用对象的方法

excel中绝对引用相对引用与快捷键相对引用图文教程

excel
excel中绝对引用相对引用与快捷键相对引用图文教程

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

《闪之轨迹2》梦幻回廊刷怪组队推荐与战术心得

《闪之轨迹2》梦幻回廊刷怪组队推荐与战术心得

Flash鼠绘教程:教你绘制一盘逼真的水仙花

Flash鼠绘教程:教你绘制一盘逼真的水仙花
下拉加载更多内容 ↓