zoukankan      html  css  js  c++  java
  • [C++] 引用详解

    引用的基础用法和本质

    引用和consts

    引用和返回

    引用的基础用法和本质
    /*******************************************************************
        a)    在C++中新增加了引用的概念
        
        b)    引用可以看作一个  已定义[变量]  的【别名】
        
        c)    引用的语法:Type& name = var; 
        
        d) 普通引用在声明时必须用其它的变量进行初始化,
            引用作为函数参数声明时不进行初始化                   
    ******************************************************************/
    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    /*---------------------------------------------------------------------*/
    struct Teacher {
        char name[64];
        int age;
    };
    
    Teacher t1;
    
    void printfT(Teacher *pT) {
        cout<< "printfT_pT->age:" << pT->age <<endl;
    }
    
    //pT是t1的别名 ,相当于修改了t1
    void printfT2(Teacher &pT) {
        //cout<<pT.age<<endl;
        pT.age = 33;
    }
    
    //pT和t1的是两个不同的变量
    void printfT3(Teacher pT) {
        pT.age = 45; //只会修改pT变量 ,不会修改t1变量
        cout<< "printfT3_pT.age:" << pT.age <<endl;
        cout<< "printfT3_t1.age:" << t1.age <<endl;
    }
    
    
    
    /********************************************************
     * 引用    最基本的一个功能就是    别名
    * 引用是内存空间的别名,字面量19没有内存空间 *******************************************************
    */ int main01(void) { int a = 10;//c编译器分配4个字节内存 a是内存空间的别名 int &b = a; //b就是a的别名 a = 11; //直接赋值 printf("a:%d ", a);//11 int *p = &a; *p = 12; printf("a:%d ", a);//12 b = 14; printf("a:%d b:%d", a, b);//14 14 return 0; } /******************************************************** * printfT(Teacher *pT) 结构体指针 * printfT2(Teacher &pT) 引用 * printfT3(Teacher pT) 形参 ********************************************************/ int main02(void) { //05复杂数据类型 的引用 t1.age = 35; printfT(&t1);//取t1的地址 printfT2(t1); //pT是t1的别名 printf("printfT2_t1.age:%d ", t1.age); //33 /*函数调用,实参传递给形参时,不是用实参替换(取代)形参,而是用实参给形参赋值*/ /*我在github上写了一份代码,你可以clone一份给自己,但是不会影响我的代码*/ printfT3(t1);// pT是形参 ,t1 copy一份数据 给pT //---> pT = t1 printf("t1.age:%d ", t1.age); //33 cout<< "hello..." <<endl; return 0; } /******************************************************** * 引用在C++中的内部实现是一个【常指针】 * * Type& name <==> Type* const name * ********************************************************/ int main03(void) {//引用的本质 int a = 10; int &b = a;//单独定义的引用时,必须初始化; int &c = b; b = 11; cout << "c-->" << c << endl; printf("a:%d ", a); printf("b:%d ", b); printf("&a:%d ", &a);//2424372 printf("&b:%d ", &b);//2424372 printf("sizeof(b) %d", sizeof(b));//4 引用有地址,引用是一个常量 return 0; /* 引用在C++中的内部实现是一个【常指针】 Type& name <==> Type* const name C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。 从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏 */ } /*------------------------------承接上面------------------------------*/ void func(int &a) { a = 5; } void funx(int* const a) { //常指针a *a = 7; } int main(void) { int x = 10; func(x); cout << "func(10):" << x << endl; funx(&x); cout << "funx(10):" << x << endl; return 0; } /*======================== ====================== END File ========================== =====================*/
    引用和const  
    引用是引用,const是const
    /*_________________________________________________________________________
    
    1)普通引用 int& e1 相当于 int* const e1  常(量)指针
    
    2)常引用  const int& e1  相当于 const int* const e1
    
        在C++中可以用const来声明引用  引用 <=> const引用】 
            
          -> const引用让变量e1本身和其所指向的内存空间均只拥有只读属性
    const引用分 变量的常引用 和 常量的常引用 两种 A.变量的常引用
       const Type& name = var; 存在内存泄露 B.常量的常引用
      引用是内存空间的别名 字面量19没有内存空间   当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名   使用字面量对const引用初始化后,将生成一个只读变量 __________________________________________________________________________
    */ #include <iostream> using namespace std; int main(void) { /*================================= 使用变量初始化const引用 ===============================*/ int k1 = 0; const int& rk = k1;//变量的常引用 const int* const rk = k1; // rk = 1;//err 不可以通过引用rk修改k1 k1 = 1;//ok cout << " k1:" << k1 << " rk:" << rk << " &k1:" << &k1<< " &rk:" << &rk << endl; //可以通过指针来修改rk,然后就修改了k1 int *p = (int* )&rk; //取rk的地址赋值给p 其实这里存在一个内存泄露,因为rk本身和rk的内存空间均是不可修改的,而这里修改了 *p = 11; cout << " k1:" << k1 << " rk:" << rk << " &k1:" << &k1 << " &rk:" << &rk << endl; /*=========================== 使用字面量常量初始化const引用 ===============================*/ const int b = 10;//只是一个常量b // b = 11; //err cout << " &b:" << &b << endl; // int &a = 19;//err 引用是内存空间的别名 字面量19没有内存空间 const int &a = 19;//ok 这里是引用a cout << " a:" << a << endl; cout << " &a:" << &a << endl; return 0; }

    引用和返回

    /*________________________________________________________________________ 
    
    C++引用使用时的难点:
    
        当函数返回值为引用时
    
            若返回栈变量
    
                不能成为其它引用的初始值
    
                不能作为左值使用
    
            ===>不能返回局部变量的引用
    
             
    
            若返回静态变量或全局变量
    
                可以成为其他引用的初始值
    
                既可作为右值使用,也可作为左值使用
    
                
    
        C++链式编程中,经常用到引用,运算符重载专题
    
    ____________________________________________________________________________*/
    
    #include <iostream>
    #include <cstring> //memset
    #include "stdlib.h"//malloc
    #include <cstdio>
    
    using namespace std;
    
    
    
    /***********************************************
    对比同一种类型的两种即可看出引用的优势
    ***********************************************/
    
    
    
    /*------    局部参量返回作引用     -------*/
    /*
                 error        
        
    int& getAA2() {
        int a = 10;
        return a;
    } 
    */
    
    
    
    /***********************************************************************************
     * 全局参量返回作引用
     *     以返回值的形式返回, 系统生成要返回值的副本(即临时变量)
    
     *      以引用的形式返回,   系统不生成返回值的副本
    ,
     ***********************************************************************************/
    float temp; //定义全局变量temp
    float  fn1(float r); //声明函数fn1
    float& fn2(float r); //声明函数fn2
    
    
    
    float fn1(float r) {//定义函数fn1,它以返回值的方法返回函数值
        temp = (float)(r*r*3.14);
        return temp;
    }
    
    
    
    float& fn2(float r) {//定义函数fn2,它以引用方式返回函数值
        temp = (float)(r*r*3.14);
        return temp;
    }
    
    
    
    
    /********************************************************
      * static变量返回作引用
      * 好处和全局变量一样,不用返回副本
      ********************************************************/
    int getBB1() {
        static int a = 10;
        a++;
        printf("getBB1.a:%d
    ", a);
        return a;
    }
    
    
    
    int& getBB2() {
        static int a = 10;
        a++;
        printf("getBB2.a:%d
    ", a);
        return a;
    }
    
    
    int* getBB3() {
        static int a = 10;
        a++;
        printf("getBB3.a:%d
    ", a);
        return &a;
    }
    
    
    
    
    /********************************************************
      * 形参返回作引用
      ********************************************************/
    int g1(int *p) { 
        *p = 100;
        return *p;
    }
    
    
    
    int& g2(int *p) {
        *p = 100;
        return *p;
    }
    
    
    
    /*------    指针返回作引用    -------*/
    
    struct Teacher {
        char name[64];
        int age;
    };
    
    
    
    int getTe(Teacher* *myp) {
    
        Teacher* p = (Teacher* )malloc(sizeof(Teacher));//dynamic memory
        if (p ==NULL)     return -1;
        memset(p, 0, sizeof(Teacher));
        p->age = 33;
        *myp  = p;//
        return 0;
    }
    
    
    
    int getTe2(Teacher*  &myp) {
        myp = (Teacher *)malloc(sizeof(Teacher));
        myp->age = 44;
        return 0;
    }
    
    
    
    
    
    int main() { //主函数
    
    /*===================   局部参量返回作引用         ==============================*/
    
    //    int  a2  = getAA2();        
    
    /********因为不能从被调函数中返回一个临时变量或局部变量的引用*********/
    
    
    /*====================    全局参量返回作引用        ==============================*/
    
        float a = fn1(10.0); //第1种情况,系统生成要返回值的副本(即临时变量)
        
    //    float &b = fn1(10.0); //第2种情况,可能会出错(不同 C++系统有不同规定)
        /*因为不能从被调函数中返回一个临时变量或局部变量的引用*/
        
    //用引用去接受函数的返回值,是不是乱码,关键是看返回的内存空间是不是被编译器回收了
    
        float c = fn2(10.0); //第3种情况,系统不生成返回值的副本
    /*    可以从被调函数中返回一个全局变量的引用  */
    
        float &d = fn2(10.0);//第4种情况,系统不生成返回值的副本
    /*    可以从被调函数中返回一个全局变量的引用   */
    
        cout<<    "a: " << a <<" c: " <<c    <<" d: " <<d   <<endl;
    
    
    
    /*======================   static变量返回作引用   =============================*/    
    
        int  b1  = getBB1();
        int  b2  = getBB2();
        int *b3  = getBB3();
        
        printf("b1:%d  b2:%d  b3:%d
    ", b1, b2, *b3);    
    
    /*======================   形参返回作引用   =============================*/    
    
        int  cc = 10;
        
        int  c0 = g1(&cc);    
        int  c1 = g2(&cc);
        int& c2 = g2(&cc);
    
        //用引用去接受函数的返回值,是不是乱码,关键是看返回的内存空间是不是被编译器回收了
        printf("c0:%d   ", c0);
        printf("c1:%d   ", c1);
        printf("c2:%d 
    ", c2);
    
    /*======================   类返回作引用   =============================*/
    //涉及到copy构造函数  和  =操作重载
    
    /*=================================     指针引用     ===============================*/
        Teacher *p = NULL;
    //    getTe(&p);//C语言中,修改p的值,只能发送p的地址
        getTe2(p);//C++中有了引用,可以直接传递p
        printf("age:%d 
    ", p->age);
        //因为是在子函数getTe内部开辟了一个动态内存,所以可以跨函数使用内存 
    /*
    
        关于 C指针 的几点回顾    
            1. fun(p1, p2); void fun(char *a, char *b); 
                传的是谁,谁就是实参(指针p1, p2)!
                形参(指针 a,b)的变化是不会影响实参(指针p1, p2)的变化的!
                
            2.getTe(&p);
                C语言中,修改p的值,只能发送p的地址,且如果跨函数使用内存,必须开辟动态内存
    */    
        return 0;
    }
  • 相关阅读:
    软件设计项目进展01 2019/8/19
    mysql中使用utf-8乱码
    mysql学习
    eclipse中怎么查看jsp生成的java代码
    tomcat配置出现问题
    关掉win10下面的ctrl+alt+up/dowm
    java程序运行时内存分析
    java内部类
    Struts2 ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging
    win10下 Edge和IE浏览器都不能上网,而其他浏览器可以。怎么办?
  • 原文地址:https://www.cnblogs.com/-Mr-y/p/7789319.html
Copyright © 2011-2022 走看看