分享
 
 
 

引用的作用

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

引用的作用

作者: panic

2005年3月27日

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

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()这种拖沓的语句来访问一个深层的成员。

引用的另一个作用,就是“别名”。别名是引用的另一种翻译,很明确的表达了引用的另一个作用。仅仅是为了代码的可读性:

//下面的代码

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下的表现却不尽如人意,因为它存储了一个指针用来取代语法上的引用,这导致类体积不必要的扩张,是我们所不希望看到的。也许在实现上确实存在难度,不过还是希望有更好的编译器能实现真正意义的引用接口。

这个例子其实是上面深层数据成员访问的一个引申。

引用,作为C++的一个特殊手法,也许还有很多不为人知的作用等待我们去发掘呢~

注:文中的代码并未经过严格测试,有兴趣的读者可以自己测试代码的有效性。

本文引用的 乾坤一笑 的内容均出自:

http://blog.vckbase.com/smileonce/archive/2005/03/27/4081.html

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有