c++引用规则

  首先,引用是C++引入的新语言特性,是一个变量的别名, 它必须指向一个实实在在的地址(且这个地址要在引用产生作用时还在内存中),系统始终不为其分配内存,只是新建了一对对应关系。正因如此,
1、引用必须在定义时初始化,且初始化后程序不能改变此引用关系(引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。)
2、所以允许指针的引用,而不允许引用的指针。

C++中有四种引用方式:
1、 独立引用。
      如 int  a = 5;   int & ref = a;
     // cout<<&a<<"  "<<&ref<<endl;  可以检测到二者是同一个地址 0013FF60  0013FF60


2、 返回引用。
int & get( int * a, int i ) {
  return  *(a+i);        }  // 返回数组的 i+1 个元素的值

void main() {
 int array[4] = {1, 2, 3, 4 };
 int i = 0;
 i = get( array, 2 );
 cout<<i<<endl;      // 结果为3
 system( "pause" );
}
// 补:  引用作为返回值,必须遵守以下规则:(参考: http://hi.baidu.com/pavelliu/blog/item/33ec8a35876ddc1191ef395b.html

  (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了'无所指'的引用,程序会进入未知状态。

  (2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

  (3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

  (4)引用与一些操作符的重载:

  流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << 'hello' << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

3、引用作为函数的参数。(也是最重要的,因为引用作为另一个变量的别名用处不是很大,除非变量名很长,呵呵..)
能保证参数传递中不产生副本,提高传递的效率(在传递如类对象或其它较大的数据块时非常有用),且通过const的使用,保证了引用传递的安全性。
如我们最习惯的 void swap ( int & a, int & b ) { int temp =a; a = b; b = temp; } 函数

这里要注意了,引用参数的类型一定要一致,其中要注意避免下面代码的错误:
int & get( /* const */ int & a  ) { return a; }
void main() {
get ( 5);
}          //  error C2664:“get”: 不能将参数 1 从“int”转换为“int &”
          // 把 get 的参数前 加上 const ,问题解决
其实这在其它的参数传递和赋值操作时也要注意的一点:(我理解为操作const变量的权限小于非const的权限,所以const向非const转换(如赋值)时可以,反之则不然)


4、引用和多态

  引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。
class  A;
class  B:public A{……};
B  b;
A  &Ref = b; // 用派生类对象初始化基类对象的引用

  Ref 只能用来访问派生类对象中从基类继承下来的成员,是基类引用指向派生类。如果A类中定义有虚函数,并且在B类中重写了这个虚函数,就可以通过Ref产生多态效果。

 

好,小结好了,我们来看看我的愚蠢的错误吧;

代码中三个函数的声明:
Node<Node_entry> * Stack::Gettop();    Stack<int> ms;
int size ( Node<Node_entry> * ptr ); 
Node<Node_entry> * Inverse ( Node<Node_entry> * & ptr );
 其中size的实参可以是 ms.Gettop(); 而 Inverse 的实参写成 ms.Gettop();  产生编译错误://  error C2664:
“Inverse”: 不能将参数 1 从“Node<Node_entry> *”转换为“Node<Node_entry> *&” ;
此时只能采用如下形式:
Node<int> * temp1 =  ms.Gettop();
Node<int> * temp = Inverse( temp1 );

Then, Why ??

其实很简单,正如引用的实质一样,它必须指向一块有内存的变量。而这里的实参,
这个ms.Gettop()是函数返回值,是个 临时变量 , 不可以在引用参数中作为实参.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值