第九章 引用

第九章 引用

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最好在一个函数体内(为了避免指针混淆,最好在哪创建在哪释放)

原文地址:https://www.cnblogs.com/zenseven/p/3734873.html