C++中的引用详解

来源:互联网 发布:淘宝支付宝是马云的吗 编辑:程序博客网 时间:2024/06/05 10:42

1.引用的本质 

   

   在 C/C++中,变量仅能且只能通过两种方式被访问、传递或获取。即:

        通过值 访问 / 传递变量

        通过地址 访问 / 传递变量 – 这种方法就是指针

   引用常被认为是变量的别名,实际上 C++ 中根本就没有什么叫做别名的定义。引用变量也就是个指针变量,它也拥有内存空间。最关键的是引用是一种会被编译器自动解引用的指针。引用本质上被编译成指针常量(constant pointers)。这意味着:
int &i = j  --->   int *const i = &j 

引用的常见例子

#include <iostream.h>int main(){    int i = 10;    int &j = i;<pre name="code" class="cpp">    int* const k=&i;      j++; cout<<i<<j<<*k<<endl; //相同的值 11 11 11    (*k)++;    cout<<i<<j<<*k<<endl; //相同的值 12 12 12    cout<<&i<<&j<<k<<endl;//相同的 地址      return 0;}

       为什么打印相同的地址?引用变量时会被编译器自动解引用,诸如"cout << &j << endl;"的语句,编译器就会将其转化成语句"cout << &*j << endl"。

    这样来理解。如前描叙,j实际为指针常量,即int *const j= &i。所以语句"cout << &i << &j<< endl"变为"cout << &i << &*j<< endl"也就是"cout << &i << j<< endl"。所以打印相同的地址。


2.引用的级联(cascading)

看下面的代码

#include <iostream.h>int main(){    int i = 10; // A Simple Integer variable    int &j = i; // A Reference to the variable    int &k = j; // A reference to a reference variable    int &l = k; // A reference to a reference to a reference variable.     cout<<i<<","<<j<<","<<k<<","<<l<<endl;// The print should be 10,10,10,10    j++;    cout<<i<<","<<j<<","<<k<<","<<l<<endl;// The print should be 11,11,11,11    k++;    cout<<i<<","<<j<<","<<k<<","<<l<<endl;// The print should be 12,12,12,12    l++;    cout<<i<<","<<j<<","<<k<<","<<l<<endl;// The print should be 13,13,13,13    return 0;}

   不依赖编译器的自动替换功能,手动进行替换也能达到相同的目标。上面的代码等同于

#include <iostream.h>int main(){    int i = 10;            int *const j = &i;       int *const k = &*j;      int *const l = &*k;         cout<<i<<","<<*j<<","<<*k<<","<<*l<<endl;// The print should be 10,10,10,10    (*j)++;     cout<<i<<","<<*j<<","<<*k<<","<<*l<<endl;// The print should be 11,11,11,11    (*k)++;     cout<<i<<","<<*j<<","<<*k<<","<<*l<<endl;// The print should be 12,12,12,12    (*l)++;    cout<<i<<","<<*j<<","<<*k<<","<<*l<<endl;// The print should be 13,13,13,13     return 0;}

     其中j,k.l的value都是i的地址


3.引用占据内存

#include <iostream.h>class Test{    int &i;   // int *const i;    int &j;   // int *const j;    int &k;   // int *const k; };int main(){        cout<<"size of class Test = "<<sizeof(class Test)<<endl;// This will print 12 i.e. size of 3 pointers    return 0;}

        C++标准并没有解释编译器如何实现引用的行为。所以实现取决于编译器,而大多数情况下就是将其实现为一个const指针。因此引用仍然占据内存。



4.引用支持虚函数机制

#include <iostream.h>class A{public:         virtual void print() { cout<<"A.."<<endl; }};class B : public A{public:         virtual void print() { cout<<"B.."<<endl; }}; class C : public B{public:         virtual void print() { cout<<"C.."<<endl; }};int main(){         C c1;         A &a1 = c1;         a1.print(); // prints C,此时实质为基类指针变量         A a2 = c1;         a2.print(); // prints A,此时实质为 A a2=(A)c1         return 0;}

   引用支持虚函数机制,而虚函数的动态信息只有通过指针实现。更加说明引用其实就是一个const指针。

   


5.数组引用和常量引用 

  ❶数组引用

#include"iostream"using namespace std;void display(const int a[],int length){    int i=0;while(i<length)  {cout<<a[i]<<"   ";i++;}}void add(int a[],int length){    int i=0;while(i<length)  {a[i]++;i++;}}int main(){int a[5]={0};int (&b)[5]=a;display(a,5); cout<<endl; //输出 0 0 0 0 0display(b,5); cout<<endl; //输出 0 0 0 0 0add(b,5);display(a,5); cout<<endl;//输出 1 1 1 1 1display(b,5); cout<<endl;//输出 1 1 1 1 1return 0;}

  ❷常量引用

#include"iostream"using namespace std;int _tmain(int argc, _TCHAR* argv[]){int a = 30;const int &b = 30;cout <<"a= " << a << "\tb= " << b << endl;//30 30a = 40;cout << "a= " << a << "\tb= " << b << endl;//30 40return 0;}

   ❸对于指针也有对应的引用。


6.引用作为形参和返回类型

           Person old;
           Person new=old;

          在JAVA中,使用引用传递,修改old则new值也变化。C++中除数组外,默认为值传递,即隐式的调用了Person类的默认拷贝构造函数。C++中同类型的对象赋值基本为值传递。

    引用做为形参,能够避免拷贝时间,提高效率。但是不能传递局部变量给上一级引用变量。如:

Person test(Person &p){       .......return p;}Person &pNew=test(p);//报错

           因为return p到 =test(P)过程中间,程序调用了默认拷贝函数,生成了一个test函数局部域的临时Person对象,而临时变量在test函数结束的时候销毁了。因为引用类型变量时必须初始化为一个已经定义并且有效的对象,所以调用失败了。

     ❷引用也可以作为传递类型,这时候复制不会调用拷贝构造函数:

Person& test(Person &p){       .......     return p;}Person &pNew=test(p);//不调用拷贝函数Person pNew=test(p);//调用拷贝构造函数

  

   

7.总结


    C++标准规定,引用可以占内存也可以不占,取决于编译器实现。

    ❶占内存的实现就是使用指针了。很多编译器为了简单都全部采用这种实现方法。

    ❷不占内存的实现,是引用和引用的对象在同一个函数中的时候。局部变量名其实是一个相对于栈基址的偏移量,这种情况下你定义这个局部变量的引用,编译器可以直接给这个引用赋同样的偏移值,这样引用名和变量名完全没有区别。这就是别名的含义了。

    ❸引用为形参只有用指针实现这种方法。例如换值函数swap,以下两种定义等同:

                  void swap(int const* a,int const * b )                    void swap(int&a, int&b)

 



参考:

    1.深入分析C++引用

     2.C++中的引用








0 0
原创粉丝点击