当前位置:天才代写 > tutorial > C语言/C++ 教程 > 引用的浸染

引用的浸染

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:322

众所周知,引用作为函数参数可以制止参数工具的特别拷贝,对付非内置范例,一般而言可以得到更高的效率,同时比指针更安详,语义也更清晰。可是除此之外引用有什么出格的浸染呢?在同一个浸染域的引用,就像这样:

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();直观多了。

#p#分页标题#e#

你可以用 CA a; a.i会见CA的私有数据成员,到达像属性要领那样的结果。可是这个要领在VC6下的表示却不尽如人意,因为它存储了一个指针用来代替语法上的引用,这导致类体积不须要的扩张,是我们所不但愿看到的。也许在实现上确实存在难度,不外照旧但愿有更好的编译器能实现真正意义的引用接口。

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

引用,作为C++的一个非凡手法,也许尚有许多不为人知的浸染期待我们去掘客呢~

注:文中的代码并未颠末严格测试,有乐趣的读者可以本身测试代码的有效性。

 

    关键字:

天才代写-代写联系方式