1. 对象的定义:
对象是指一块能存储数据并具有某种类型的内存空间;
一个对象a,它有值和地址&a,运行程序时,计算机会为该对象分配存储空间,来存储该对象的值,我们通过该对象的地址,来访问存储空间中的值;
2. 指针的定义
指针:它保存一个值(或 null)的地址,可以检索指向该地址处的值 。
指针定义时,可以不用初始化;
指针可以初始化为NULL,
指针的在初始化后, 其地址值仍可以改变, 用于存储另外一个地址;
指针p也是对象,它同样有地址&p和存储的值p,只不过,p存储的数据类型是数据的地址。
如果我们要以p中存储的数据为地址,来访问对象的值,则要在p前加解引用操作符"",即p。
3. 指针的常量和变量之分
对象有常量(const)和变量之分,
既然指针本身是对象,那么指针所存储的地址也有常量和变量之分;
指针常量是指,指针这个对象所存储的地址是不可以改变的,
而指向常量的指针的意思是,不能通过该指针来改变这个指针所指向的对象。
4.引用
引用用于在程序的不同的部分使用两个以上的变量名指向同一块地址,
使得对其中任何一个变量的操作实际上都是对同一地址单元进行的。
引用的特点:
-
引用仅是变量的别名,而不是实实在在地定义了一个变量,因此引用本身并不占用内存,引用,表明上是为变量创建了第二个名字, 它的本质是一个指针,和目标变量的是同一个内存地址声明引用时,目标的存储状态不会改变;
-
引用在定义时,必须初始化, 且不能初始化为空;只有在引用申明时, “&” 才称作引用符,且放在类型名后面;其他时候出现的 “&”, 都是指 取地址操作符;。
-
引用只能在初始化的时候引用一次 ,不能更改为转而引用其他变量。
-
对引用进行操作,实际上就是对被引用的变量进行操作;
5. C++ 中为什么要有 “引用”
C++ 中引用的出现,最初是为了解决, 运算符重载的 问题;
假设没有引用,那么,用指针来operator overloading操作。 A operator +(const A *a, const A *_a);
那么使用的时候,&a + &b, 这样看起来不是那样简单明了。
引用解决C++运算符重载后代码美观的问题。
并且引用的 出现带来了 一个指针无法替代的特性: 引用临时对象;
引用在定义的时候必须就赋值,并且此后再也无法更改;
5.1 引用的特性
并且在实践中,使用指针,经常出现一下情况:
- 操作空指针
- 操作野指针
- 不知不觉中, 手动改变了指针的值,随后以为该指针正常,关键本人不知道;
为了设立一种机制, 保证上述三种情况的不发生, “ 引用”这个机制保证避免发生上述三种情况;
引用特性:
- 引用不允许为空 (从而避免了操作空指针)
- 引用在定义的时候,就必须初始化(避免了操作 野指针)
- 一个引用 ,始终从一而终的指向他 初始化的那个对象 ( 避免了指针的值不会被修改)
5.2 引用作为函数参数
C++ 支持把引用作为参数传给函数, 这比传一般的参数更安全
(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作:
- 而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;
- 如果传递的是对象,还将调用拷贝构造函数。
- 因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;
另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。
5.3 引用作为函数的返回值
(1)以引用返回函数值,定义函数时需要在函数名前加&
(2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
引用作为返回值,必须遵守以下规则:
1.不能返回局部变量的引用。
主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
2.不能返回函数内部new分配的内存的引用。
例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
3.可以返回类成员的引用,但最好是const。
这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
4.引用与一些操作符的重载
流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << “hello” << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。