foxmanzj 回复于:2004-04-18 17:07:33 |
关注这篇帖子,希望有会的不吝赐教。 |
xhl 回复于:2004-04-18 22:43:31 |
typedef int arri[4];
arri a1; arri &ref = a1; 这是什么语法,没有见过。不知道是写错了,还是有这种用法! |
yangtou 回复于:2004-04-19 00:12:18 |
只学过一点c++,觉得楼主说的有道理 |
whyglinux 回复于:2004-04-19 11:36:28 |
[quote:81ce591d5f="THEBEST"]我在C++ PRIMER PLUS上看到作者在建议用指针还是引用时说出:如果数据对象是数组,则使用指针。因为这是唯一的选择。
为什么?不可以将引用作用在数组上吗? EG: typedef int arri[4]; arri a1; arri &ref = a1; 不是一样可以? [/quote:81ce591d5f] 首先说明,象上面程序中的这种对数组名的引用是完全可行的。在定义的时候,只要是:"type" + "&" + "reference"这种形式,都可以用来定义一个对 type 类型的名叫 reference 的引用,不论 type 是基本类型、类还是其它自定义类型。上面定义的引用 ref 其作用就是用另外一个不同于数组名的名称 ref 来代替原来的数组名 a1。除非你原来的数组名由于过长导致书写不便或者难于记忆,从而想用一个较短易记的别名(引用)来代替它之外,这样做没有任何其它的好处,也就是说象上面那样仅仅为了使用引用 ref 访问被引用的对象 a1 从而定义这样一个引用是没有必要的。 引用的主要作用是用作函数的参数或者函数的返回值。(这样做的好处就是:对于同一类型的引用(不同类型的引用例外,如下面第二部分程序中所示的那样。但是在实际中几乎用不到这种引用),直接访问的是被引用的对象本身,虚实参数结合或者函数返回的时候不会额外产生拷贝对象到临时对象的操作,与指针访问具有同等的效率,但在使用上比指针访问更加直观。) 例如,我们可以用上面程序中提供的 arri 类型定义这样一个函数:void f( arri& r ),r 就是对arri 类型的引用。可以这样调用这个函数:f( a1 ),这样在函数内对虚参 r 的操作实际上就是对 a1 数组的操作。一个特别的地方就是在函数 f 内可以通过虚参 r 得到数组的长度:sizeof( r )/sizrof( r[0] )!想一想这也是很自然的:引用只是一个别名,它继承了被引用对象的全部属性,与被引用对象是等同的。从而,arri类型实际上除了 int 之外,还包含了数组大小的信息。 但是这样定义函数有着很大的弊端:函数 f 的应用受到了巨大的限制。由于类型 arri 实际上就是 int[4],表示一个有 4 个元素的整型数组,所以函数 f 的实参只能是具有 4 个元素的整型数组名,而对于另外长度的数组,即使是整型数组,也是不能作为实参传递给这个函数的。在实际应用中,大多数情况下数组的长度事先是不能确定的(一般仅能预先确定数组的最大长度。这已经不错了;有时连数组的最大长度都无法事先估计),因此象上面那样在函数参数中定义对数组的引用也就失去意义了。可能是由于这个原因,所以才有了上面“如果数据对象是数组,则使用指针”的说法吧。 [quote:81ce591d5f="THEBEST"]还有在TCPL上讲: 引用: 需要区分对变量的引用和对常量的引用,是因为在变量引用的情况下引进临时量极易出错,对变量的赋值将会变成对于----即将消失的=====临时量的赋值。 怎么会出现这种情况呢?因为出现引用到临时量上的情况有两种: 1>不同类型之间引用。2>非左值。 那它非得通过const引用才可以呀。如果再通过引用来对被引用的量赋值呀? 怎么有机会去对临时量的赋值呢?能对作用说的这个意思举个例吗? [/quote:81ce591d5f] 对于非左值的引用必须是 const 引用才可以。但是,对于不同类型之间的引用可以是非 const 的引用,举例如下: [code:1:81ce591d5f] void ff( int& m ) // not this form: void ff( const int& m ) { cout << "in ff() at first, m = " << m << endl; m = 9; // m is a reference to a temporary int, not a reference to x; the temporary int is set to 9 by its reference m. cout << "in ff() after assigned, m = " << m << endl; } int main() { float x = 5.3; cout << "before ff(), x = " << x << endl; ff( (int&)x ); // x is a float while m is a reference to int cout << "after ff(), x = " << x << endl; } [/code:1:81ce591d5f] 在我的机器上运行结果如下。 before ff(), x = 5.3 in ff() at first, m = 1084856730 in ff() after assigned, m = 9 after ff(), x = 1.26117e-44 其中函数 ff 中参数 m 不是对 x 的引用了,而是对内存中一个临时整型对象的引用,所以 x 得不到预期的结果(9.0)。之所以 x 得到改变,是因为 gclearcase/" target="_blank" >cc 编译器把 m 引用的临时对象的地址就设置为实参 x 的首地址,从而通过 m 改变了临时变量的值,也就改变了实参 x 的值。其它编译器是否也是这么处理的还有待证实。 对于 const 引用,不允许用这个引用改变被引用的对象;即使是由于类型转换等原因 const 引用变成了对临时生成的对象的引用,也不会允许对这个临时对象作任何改变,即不存在向这个临时对象的赋值问题。所以,const 引用的唯一作用就是只能使用被引用的对象,对被引用的对象实际上不能施加任何影响,即不能通过 const 引用改变被引用的对象,当然也就不存在上面所说的由于通过引用实际上是给临时对象赋值而产生的问题了。 |
THEBEST 回复于:2004-04-19 14:10:21 |
[quote:41bd0d578d]因为 gcc 编译器把 m 引用的临时对象的地址就设置为实参 x 的首地址,从而通过 m 改变了临时变量的值,也就改变了实参 x 的值。[/quote:41bd0d578d]gcc為什麼決定這樣做呢?
这样做的话对x还产生影响。 而如果它只是改变临时对象的话那不更好。(只是对用户的感觉产生影响而不会影响到原来的x值啊) 它为什么把m引用的临时对象的地址就设置为实参的首地址? 这样的话就不存在那个什么临时对象了呀?为了节省空间? |
whyglinux 回复于:2004-04-19 23:12:31 |
>> gcc為什麼決定這樣做呢?
>> 这样做的话对x还产生影响。 >>而如果它只是改变临时对象的话那不更好。(只是对用户的感觉产生影响而不会影响到原来的x值啊) 如果gcc不这么做的话,你可能就又要问那为什么不决定这样做呢?说到底,只是一个人为的规定而已。你在函数参数中用非 const 引用的目的就是想在函数中通过这个引用来操作原来被引用的对象的,从这一点上说,gcc的这种规定至少让你能看到通过引用改变了被引用的对象(虽然有时可能不是你所期望的结果),比对被引用的对象毫无影响要好一些吧。当然这样做也有它的缺陷,在下面我还会提到。 >> 它为什么把m引用的临时对象的地址就设置为实参的首地址? 理由同上。 >> 这样的话就不存在那个什么临时对象了呀?为了节省空间? 在上面我给出的程序中,函数 ff() 中临时对象就是以实参为首地址的一个整型空间,m 就是对这个临时对象的引用(就象共用体一样,float型的实参 x 和 int 型的临时对象共用同一内存空间)。这样做除了节省空间外,最主要的原因可能就是处理简单吧。由于下述的两个原因导致了使用不同类型之间的引用是无效的和不安全的,因此应该避免对不同类型之间的引用的使用。可能是基于这一点,编译器没有对此作过多的处理。 1. 我上面也已经提到过,不同类型之间的引用虽然是合法的,但是由于类型转换过程中临时对象的产生,存在着使用上的问题。这就如同一个指向 int 型的指针,你一定要把它作为一个指向 float 型的指针使用一样(通过强制类型转换可以做到这一点),虽然是合法的,但是却是应该避免的,因为这样做一般没有实际上的意义。 2. 在我给出的程序中给出了 float 型转换到 int 型的引用,一般 sizeof( float ) >= sizeof( int ),所以还没有严重的安全问题。如果是类似 char 型转换到 int 型这样的 sizeof( char ) < sizeof( int ) 的引用转换,转换之后变成了对整型的引用,会改变 char 之后的内存空间,这样带来的问题就很严重了。 同种类型的引用不产生临时对象,没有上述缺点,所以可放心使用。 |