zoukankan      html  css  js  c++  java
  • 第九章 引用

    第九章 引用

    1.  什么是引用?

    引用就是别名。int &ra=a;此处的&不是取址运算符,而是引用运算符

    3.  引用就是别名常量

    4.  引用对象

    只能 int &ra=a;// 注意定义引用时要对其初始化

    int &ra;

    ra=a;  //这样是错误的,引用就像常量,只能初始化不能赋值

    对象也可以定义一个引用,但是类不能,因为它没有具体的内存地址

    5.  空引用

    指针删除后需要赋空,引用不需要

    6.  按值传递

    按值传递(传递的是副本)≠按地址传递()≠按别名传递(有什么不同?)

    9.1.利用指针返回多值

    9.2.用引用来返回多值 

    使用指针或者别名传递变量允许在被调函数体内改变原来的变量,因此可以借此返回多个函数值;

    ☆10.  按值传递对象

    何时使用复制构造函数按值传递对象(参数)函数(按值)返回对象(return)用一个对象初始化另一个对象即复制初始化时(初始化)根据元素初始化列表初始化数组元素。这四种情况都将调用复制构造函数。记住,复制构造函数只能用于初始化,不能用于赋值,赋值时不会调用复制构造函数,而是使用赋值操作符

    11.  按址传递对象

    (避免调用复制构造函数的方法)

    A *func(A *one);

    int main()

    A  a; 

    func(&a);

         cout<<func(&a)<<endl; 

    return 0;

    }

    A *func(A *one){   return one(地址); }

    12.  使用const指针来传递对象

    使用const为按址传递提供保护机制(类似实现了值传递的功能)

    A const*const func(const A * const one)const{return one;}

    const A * const p=func(&a);

    a.set(44);

    a.set(88);

    每个const都有不同意思,还有const不管怎么加都不会修改实参变量的属性(不懂看视频)

    int get()const { x=5;return x;}

    这里const不能改变成变量的值

    13.  按别名来传递对象

    由于引用是常量不能被分配给另一个对象,所以与指针相比省了两个const

    A const &func(const A &one)const{return one}

    A& b=func(a);//在接受一个对象的别名时被接受方只能是别名,目的是为了避免调用复制构造函数

    //A b=func(a);

    14.  到底是使用引用还是指针

    这是因为指针可以为空,但是引用不能为空。指针可以被赋值,但是引用只能被初始化。不可以被赋为另一个对象的别名,①如果你想使用一个对象记录不同变量的地址,那么你只能使用指针。

    ②另外,在堆中创建一块内存区域,必须要用指针来指向它,否则这块区域就会变成无法访问的内存空间。当然我们可以用引用来引用指向内存空间的指针。

    ☆指针与引用的区别:

    指针可以为空,引用不能;

    指针可以被赋值,引用不能;

    指针可以指向堆中空间,引用不能;指针可以delete,引用不能;

    int *&r=new int;//功能等价于 int *r=new int 但这样写是有问题的,当new int 返回NULL  别名r就有问题,因为别名不能被赋空,会导致系统崩溃

    所以new一个对象是一定要用指针

    15.  引用和指针可以一块声明

    int *r,&ra=a;//只有一个指针

    16.  引用容易犯的错误(重新看视频)

    17.  调用一个按值返回的堆中对象

    //return p后p被释放 但没有delete p 就不能删除p创建的堆中对象

    //从而导致这个堆中对象不能再被访问 出现内存泄露

     1 #include "iostream"
     2 using namespace std;
     3 class A
     4 {
     5 public:
     6     A(int i){x=i;}
     7     int get(){return x;}
     8 private:
     9     int x;
    10 };
    11 A func();
    12 int main()
    13 {
    14     A rp=func();
    15     cout<<"对象rp的地址:"<<&rp<<endl;
    16     cout<<rp.get()<<endl;
    17     return 0;
    18 }
    19 A func()
    20 {
    21     A *p=new A(99);
    22     cout<<"对象*p的地址:"<<p<<endl;
    23     return *p;//按值返回,P开辟的堆中空间没有被释放
    24 }

    结果:对象rp与*p的的地址值不一样

    18.  调用一个按别名返回的堆中对象

    // r成了空引用 空引用是个隐蔽的杀手要尽量避免

     1 #include "iostream"
     2 using namespace std;
     3 class A
     4 {
     5 public:
     6     A(int i){x=i;}
     7     int get(){return x;}
     8 private:
     9     int x;
    10 };
    11 A &func();
    12 int main()
    13 {
    14     A &rp=func();//接收一个对象的别名时,被接收方只能是别面
    15     cout<<"对象rp的地址:"<<&rp<<endl;
    16     cout<<rp.get()<<endl;
    17     A *pa=&rp;
    18     delete pa;// r成了空引用 空引用是个隐蔽的杀手要尽量避免
    19     pa=NULL;
    20     return 0;
    21 }
    22 A &func()
    23 {
    24     A *p=new A(99);
    25     cout<<"对象*p的地址:"<<p<<endl;
    26     return *p;//
    27 }

    结果:对象rp与*p的的地址值一样

    18.1  调用一个按指针返回的对象(可以用,但不方便阅读

     1 //本质上没有错误,只是用起来容易忘记删除func()中的指针
     2 #include "iostream"
     3 using namespace std;
     4 class A
     5 {
     6 public:
     7     A(int i){x=i;}
     8     int get(){return x;}
     9 private:
    10     int x;
    11 };
    12 A *func();
    13 int main()
    14 {
    15     A *rp=func();//接收一个对象的别名时,被接收方只能是别面
    16     cout<<"对象rp的地址:"<<rp<<endl;
    17     cout<<rp->get()<<endl;
    18     delete rp;
    19     rp=NULL;
    20     return 0;
    21 }
    22 A *func()
    23 {
    24     A *p=new A(99);
    25     cout<<"对象*p的地址:"<<p<<endl;
    26     return p;//
    27 }
    28 //结果:对象rp与*p的的地址值一样

    ☆19.  在哪里创建,就在哪里释放

     1 //为了避免混淆我们尽量在哪里new在哪里delete
     2 #include "iostream"
     3 using namespace std;
     4 class A
     5 {
     6 public:
     7     A(int i){x=i;}
     8     int get(){return x;}
     9     void set(int i){x=i;}
    10 private:
    11     int x;
    12 };
    13 
    14 //按指针调用返回
    15 //const A * const func(A *);
    16 //int main()
    17 //{
    18 //    A *p=new A(99);
    19 //    cout<<p->get()<<endl;
    20 //    func(p);
    21 //    cout<<p->get()<<endl;
    22 //    delete p;
    23 //    p=NULL;
    24 //    return 0;
    25 //}
    26 //const A * const func(A *rp)
    27 //{
    28 //    rp->set(66);
    29 //    return rp;//
    30 //}
    31 
    32 
    33 //按别名调用返回
    34 const A &  func(A&);
    35 int main()
    36 {
    37     A *p=new A(99);
    38     cout<<p->get()<<endl;
    39     func(*p);
    40     cout<<p->get()<<endl;
    41     delete p;
    42     p=NULL;
    43     return 0;
    44 }
    45 const A & func(A &rp)
    46 {
    47     rp.set(66);
    48     return rp;//
    49 }

    本章总结:

    1.  按值传递(传递的是副本)≠按地址传递≠按别名传递

    2.  按值传递对象,会调用复制构造函数

    按址传递对象,可以避免调用复制构造函数(引用,指针)(记得与const联用)

    3.  ☆何时调用复制构造函数

    ①   同类型对象对另一对象的初始化

    ②   按值传递对象

    ③   按值返回对象

    ④   初始化顺序容器中的元素

    ⑤   根据元素初识化列表初始化数组元素

    string strs[]={string(“tonnie”),string(“john”),string(“mark”)};

    4.  ☆const为按址传递提供保护机制(类似实现了按值传递的功能)

    A const * const func(const A * const p)const{}

    A const * & func(const A * & r)const{}

    5.  指针与引用的区别

    ①   指针可以为空,引用不可以(p=NULL)

    ②   指针可以被赋值,引用不可以

    ③   指针可以指向堆中空间,用于不可以

    ④   deldete不能对引用使用

    int *&r=new int;//等价于 int *r=new int;

       但是,当机子虚拟内存太小,new int会自动返回一个空指针。而引用不能为空(非常规型),所以会导致系统崩溃

    6.  ☆int* r,&ra=a;          //只有一个指针

    7.  new和delete最好在一个函数体内(为了避免指针混淆,最好在哪创建在哪释放)

  • 相关阅读:
    HelpersSimpleCurl
    HelpersSessions
    HelpersReservedWords
    关于Java加载属性文件放在web容器不好使的解决办法
    (更新)Java + 腾讯企业邮箱 + javamail + SSL 发送邮件
    Java + 腾讯企业邮箱 + javamail + SSL 发送邮件
    struts2实现改变超链接的显示方式
    struts2 的正则表达式验证不起作用解决办法
    Hibernate5.1.0的hello word
    hibernateTools插件安装
  • 原文地址:https://www.cnblogs.com/zenseven/p/3734873.html
Copyright © 2011-2022 走看看