[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\r\n", a);//11 int *p = &a; *p = 12; printf("a:%d\r\n", 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 \n", t1.age); //33 /*函数调用,实参传递给形参时,不是用实参替换(取代)形参,而是用实参给形参赋值*/ /*我在github上写了一份代码,你可以clone一份给自己,但是不会影响我的代码*/ printfT3(t1);// pT是形参 ,t1 copy一份数据 给pT //---> pT = t1 printf("t1.age:%d \n", 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\r\n", a); printf("b:%d\r\n", b); printf("&a:%d\r\n", &a);//2424372 printf("&b:%d\r\n", &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 << "\n rk:" << rk << "\n &k1:" << &k1<< "\n &rk:" << &rk << endl; //可以通过指针来修改rk,然后就修改了k1 int *p = (int* )&rk; //取rk的地址赋值给p 其实这里存在一个内存泄露,因为rk本身和rk的内存空间均是不可修改的,而这里修改了 *p = 11; cout << "\n k1:" << k1 << "\n rk:" << rk << "\n &k1:" << &k1 << "\n &rk:" << &rk << endl; /*=========================== 使用字面量常量初始化const引用 ===============================*/ const int b = 10;//只是一个常量b // b = 11; //err cout << "\n &b:" << &b << endl; // int &a = 19;//err 引用是内存空间的别名 字面量19没有内存空间 const int &a = 19;//ok 这里是引用a cout << "\n a:" << a << endl; cout << "\n &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\n", a);
    return a;
}



int& getBB2() {
    static int a = 10;
    a++;
    printf("getBB2.a:%d\n", a);
    return a;
}


int* getBB3() {
    static int a = 10;
    a++;
    printf("getBB3.a:%d\n", 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\n", 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 \n", c2);

/*======================   类返回作引用   =============================*/
//涉及到copy构造函数  和  =操作重载

/*=================================     指针引用     ===============================*/
    Teacher *p = NULL;
//    getTe(&p);//C语言中,修改p的值,只能发送p的地址
    getTe2(p);//C++中有了引用,可以直接传递p
    printf("age:%d \n", 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;
}

 

posted @ 2017-11-05 23:07  _Mr_y  阅读(561)  评论(0编辑  收藏  举报
levels of contents