android 源码阅读之C++的引用

来源:互联网 发布:软件售后服务管理系统 编辑:程序博客网 时间:2024/05/07 02:59
用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。不创建任何副本。引用类型包括类、接口、委托和装箱值类型。

目录

引用类型 (reference type)
引用和指针的区别
引用的规则
引用的主要功能
引用在类中的使用
引用在类中使用需注意

编辑本段引用类型 (reference type)

  “引用”(reference)是c++的一种新的变量类型,是对C的一个重要补充。它的作用是为变量起一个别名。假如有一个变量a,想给它起一个别名,可以这样写:  int a;int &b=a;  这就表明了b是a的“引用”,即a的别名。经过这样的声明,使用a或b的作用相同,都代表同一变量。在上述引用中,&是“引用声明符”,并不代表地址。  不要理解为“把a的值赋给b的地址”。引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。声明引用并不开辟内存单元,b和a都代表同一变量单元。  注意:在声明引用变量类型时,必须同时使之初始化,及声明它代表哪一变量。在声明一个变量的引用之后,在本函数执行期间,该引用一直与其代表的变量相联系  ,不能再作为其他变量的别名。下面的用法不对:  int a1,a2;  int &b=a1;  int &b=a2;//企图使b变成a2的别名(引用)是不行的。这样是错误的。  我们可以把a2的值赋给b。  b=a2;

编辑本段引用和指针的区别

  看实例吧:  引用是C++中的概念,初学者容易把引用和指针混淆一起。  下面的程序中,n是m的一个引用(reference),m是被引用物(referent)。  int m;  int &n = m;  n相当于m的别名(绰号),对n的任何操作就是对m的操作。  所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。

编辑本段引用的规则

  (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。  (2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。  (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。  以下示例程序中,k被初始化为i的引用。  语句k = j并不能将k修改成为j的引用,只是把k的值改变成为6。  由于k是i的引用,所以i的值也变成了6。  int i = 5;  int j = 6;  int &k = i;  k = j; // k和i的值都变成了6;

编辑本段引用的主要功能

  引用的主要功能:传递函数的参数和返回值。  C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。  以下是"值传递"的示例程序。  由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n, 所以n的值仍然是0。  void Func1(int x)  {  x = x + 10;  }  ...  int n = 0;  Func1(n);  cout << "n = " << n =" 0" n =" 0;" n = " << n << endl; // n = 10 以下是" size="14">  void Func3(int &x) { x = x + 10; } ... int n = 0; Func3(n); cout << "n = " << n =" 10">  (1) 在实际的程序中,引用主要被用做函数的形式参数--通常将类对象传递给一个函数.引用必须初始化. 但是用对象的地址初始化引用是错误的,我们可以定义一个指针引用。  1 int ival = 1092;  2 int &re = ival; //ok  3 int &re2 = &ival; //错误  4 int *pi = &ival;  5 int *&pi2 = pi; //ok  (2) 一旦引用已经定义,它就不能再指向其他的对象.这就是为什么它要被初始化的原因。  (3) const引用可以用不同类型的对象初始化(只要能从一种类型转换到另一种类型即可),也可以是不可寻址的值,如文字常量。例如  double dval = 3.14159;  //下3行仅对const引用才是合法的  const int &ir = 1024;  const int &ir2 = dval;  const double &dr = dval + 1.0;  上面,同样的初始化对于非const引用是不合法的,将导致编译错误。原因有些微妙,需要适当做些解释。  引用在内部存放的是一个对象的地址,它是该对象的别名。对于不可寻址的值,如文字常量,以及不同类型的对象,编译器为了实现引用,必须生成一个临时对象,引用实际上指向该对象,但用户不能访问它。  例如:  double dval = 23;  const int &ri = dval;  编译器将其转换为:  int tmp = dval; // double -> int  const int &ri = tmp;  同理:上面代码  double dval = 3.14159;  //下3行仅对const引用才是合法的  const int &ir = 1024;  const int &ir2 = dval;  const double &dr = dval + 1.0;  内部转化为:  double dval = 3.14159;  //不可寻址,文字常量  int tmp1 = 1024;  const int &ir = tmp1;  //不同类型  int tmp2 = dval;//double -> int  const int &ir2 = tmp2;  //另一种情况,不可寻址  double tmp3 = dval + 1.0;  const double &dr = tmp3;  (4) 不允许非const引用指向需要临时对象的对象或值,即,编译器产生临时变量的时候引用必须为const!!!!切记!!  int iv = 100;  int *&pir = &iv;//错误,非const引用对需要临时对象的引用  int *const &pir = &iv;//ok  const int ival = 1024;  int *&pi_ref = &ival; //错误,非const引用是非法的  const int *&pi_ref = &ival; //错误,需要临时变量,且引用的是指针,而pi_ref是一个非常量指针  const int * const &pi_ref = &ival; //正确  //补充  const int *p = &ival;  const int *&pi_ref = p; //正确  (5) ********对于const int *const & pi_ref = &iva; 具体的分析如下:*********  1.不允许非const引用指向需要临时对象的对象或值  int a = 2;  int &ref1 = a;// OK.有过渡变量。  const int &ref2 = 2;// OK.编译器产生临时变量,需要const引用  2.地址值是不可寻址的值  int * const &ref3 = &a; // OK;  3.于是,用const对象的地址来初始化一个指向指针的引用  const int b = 23;  const int *p = &b;  const int *& ref4 = p;  const int *const & ref5 = &b; //OK  const引用的语义到底是什么?  最后,我们可能仍然不明白const引用的这个const的语义是什么  const引用表示,试图通过此引用去(间接)改变其引用的对象的值时,编译器会报错!  这并意味着,此引用所引用的对象也因此变成const类型了。我们仍然可以改变其指向对象的值,只是不通过引用  下面是一个简单的例子:  1 #include<iostream>  2 using namespace std;  3  4 int main()  5 {  6 int val = 1024;  7 const int &ir = val;  8  9 val++;  10 //ir++;  11  12cout <<"val="<<val<<"\n";  13cout<<"ir="<<ir;  14return 0;  15 }  其中第10行,如果我们通过ir来改变val的值,编译时会出错。但是我们仍然可以通过val直接改变其值(第9行)  总结:const引用只是表明,保证不会通过此引用间接的改变被引用的对象!  另外,const既可以放到类型前又可以放到类型后面,放类型后比较容易理解:  string const *t1;  const string *t1;  typedef string* pstring;string s;  const pstring cstr1 = &s;就出错了  但是放在类型后面不会出错:  pstring const cstr2 = &s;

编辑本段引用在类中的使用

  1. #include <iostream>  2. using namespace std;  3.  4. class A  5. {  6. public:  7. A(int i=3):m_i(i){}  8. void print()  9. {  10. cout<<"m_i="<<m_i<<endl;  11. }  12. private:  13. int m_i;  14. };  15.  16. class B  17. {  18. public:  19. B(){}  20. B(A& a):m_a(a){}  21. void display()  22. {  23. m_a.print();  24. }  25. private:  26. A& m_a;  27. };  28.  29.  30. int main(int argc,char** argv)  31. {  32. A a(5);  33. B b(a);  34. b.display();  35. return 0;  36. }

编辑本段引用在类中使用需注意

  其中,要注意的地方就是引用类型的成员变量的初始化问题,它不能直接在构造函数里初始化,必须用到初始化列表,且形参也必须是引用类型。  凡是有引用类型的成员变量的类,不能有缺省构造函数。原因是引用类型的成员变量必须在类构造时进行初始化。  如果两个类要对第三个类的数据进行共享处理,可以考虑把第三个类作为这两个类的引用类型的成员变量
原创粉丝点击