在实际应用中,引用非常适合用于结构和类,而不是普通的内置类型,如 int, double 等,对于结构的引用语法形式和其它的普通类型并没有什么区别,只要在结构名前加一个 & 即可。
下面的程序将使用结构的引用作为函数的参数,返回的也是结构的引用。
测试代码:
[C++] 纯文本查看 复制代码 #include <iostream>
using namespace std;
struct sysop {
char name[32];
char quote[64];
int used;
};
const sysop &use(sysop &sysopref);
int main()
{
sysop looper = {
"beyes",
"I am admin of groad.net",
0
};
use(looper); //将结构按引用传递给函数
cout << "Looper: " << looper.used << " use(s)\n";
sysop copycat; //再声明一个 sysop 结构
copycat = use(looper); //函数的返回直接赋给 copycat 而不需要一个临时结构变量
cout << "Looper: " << looper.used << " use(s)\n";
cout << "Copycat: " << copycat.used << " use(s)\n";
cout << "use(looper): " << use(looper).used << " use(s)\n"; //通过返回直值接使用变量
return 0;
}
const sysop &use(sysop &sysopref)
{
cout << sysopref.name << " says:\n";
cout << sysopref.quote << endl;
sysopref.used++;
return sysopref;
}
运行输出:[beyes@beyes cpp]$ ./struct_ref
beyes says:
I am admin of groad.net
Looper: 1 use(s)
beyes says:
I am admin of groad.net
Looper: 2 use(s)
Copycat: 2 use(s)
beyes says:
I am admin of groad.net
use(looper): 3 use(s) 上面程序中需要注意 3 个地方:
1. 在函数调用时,将结构 looper 按引用传递给 use() 函数,使得 sysopref 成为 looper 的别名。在 use() 函数中,在显示 sysopref 的 name 和 quote 成员时,实际上显示的是 looper 成员,同样当 ysopref.used 加 1 时实际上是 looper.used 加 1 。
2. 函数将引用作为返回值。一般情况下,返回机制是将返回值复制到一个临时存储区中,然后调用程序再去访问该区域。但是,返回引用就意味着调用程序将直接访问返回值,而不需要经过拷贝。在上面程序中, copycat = use(looper); 这个语句,如果 use() 返回的是一个普通的结构而不是引用,那么 sysopref 的内容将会被复制到一个临时的存储单元中,然后再把这个临时单元中的内容复制到 copycat 中。然而,当返回引用时,looper 的内容就直接复制到 copycat 中,中间省去了一道工序,显示出更高效率。
记住: 返回引用的函数实际上是被引用的变量的别名。
3. 程序中使用了函数调用来访问结构中的成员,如语句 cout << "use(looper): " << use(looper).used << " use(s)\n"; 。这里,如果 use() 返回的是一个结构而不是结构的引用,那么这些代码访问的将是 looper 临时拷贝的 used 成员。
返回引用时需要注意的是:不能返回函数终止时不再存在的内存单元的引用。简言之,就是不能返回局部变量的引用。同样,也要避免返回指向临时变量的指针。避免这种问题的简单方法是,返回一个作为参数传递给函数的引用。换句话来说就是,函数的参数是什么引用,那么返回的就是什么的引用。还有一种方法是使用 new 来分配新的内存空间,然后返回指向该内存空间的指针,比如:
[C++] 纯文本查看 复制代码 const sysop & clone(sysop &sysopref)
{
sysop *psysop = new sysop;
*psyop = sysopref; //拷贝
return *psysop; //返回对拷贝的引用
}
上面,第一条语句创建了一个空的 sysop 结构,并将指针 psysop 指向它,所以 *psysop 解释该结构。在最后一跳返回语句中,看上去是返回该结构,但函数的声明表明,该结构实际上返回的是这个结构的引用,因此我们可以像下面这样使用该函数: sysop &other = clone(looper); 这使得 other 成为了新结构的引用。在使用这种方法时要注意,当不需要 new 分配的内存要使用 delete 来释放它们,而调用 clone() 则隐藏了对 new 的调用,这很容易让人忘记以后用 delete 来释放内存。
此外,上面程序的返回的引用类型是 const 的,如 const sysop & 。那么 const 在此有什么用途呢?它并不意味着结构 sysop 本身就是 const ,而只是意味着不能使用返回的引用来直接修改它所指向的结构。如果省略了 const ,那么可以像下面使用代码:其等效于:use(looper);
looper.used = 10; 还可以写下面的代码:sysop newgal = { "xiaohang", "member of groad.net", 0};
use(looper) = newgal; 上面代码等效于:
[quote] sysop newgal = { "xiaohang", "member of groad.net", 0};
use(looper);
looper = newgal;[/mw_shl_code]
总之,省略 const 后,可以编写更简短,但含义更模糊的代码。然而,在通常的设计中应该避免使用模糊特性,因为模糊特性增加了犯错的机会,而将返回类型声明为 const 引用,这样就避免犯糊涂了。有时,省略 const 也是有道理的,不能一概而论。 |