面向对象的编程的一个特点就是在运行阶段(而不是编译阶段)进行决策。运行阶段决策提供了灵活性,可以根据当时的情况进行调整。具有代表性的就是,可以在运行阶段分配内存。
C语言使用库函数malloc()来分配内存;C++中可以这么用,但是更为常用的就是用new运算符来分配内存,在了解new运算符时你最好已经知道C++的指针是怎么回事。
先来看一个简单的例子:
例如通常情况下,我们需要创建一个指向int类型的指针,程序就会如下:
int a =1;
int *point = &a;
这样,在程序的编译阶段,int变量a的地址就会赋值给int类型的指针point。
如果,在程序运行阶段,为一个int值分配未命名的内存,程序就会如下:
int* point2 = new int;
等号左边表示我定义了一个指向int类型的指针,等号右边,我用运算符new开辟一个可以存储int类型数据的内存区域(因为不同类型的变量需要占用的内存不同),返回此区域的地址。
通过上面那行程序,我就得到了一个内存块,但是我并不知道此内存块的名字,因为我没有给它命名,但是,我知道这片儿区域的地址,point2. 如果我需要取得这个内存块中存储的值,可以用 *point2 , 这就相当于是一个int变量了
举一个通俗的例子来描述上述过程,比如我们通常都不知道我们寝室叫什么名字,因为通常我们不会给寝室取名字,开学的时候,我们去报道,首先明确类型,我是本科生,学校就分给我一个本科生的宿舍(4人间),然后返回此寝室的地址,比如1栋101:1101.然后以后要找我们寝室这四个人,都是直接说1101寝室的同学。
使用new开辟内存之后,你要记得最后要用delete来释放内存,比如你毕业了,就得卷铺盖卷从寝室搬出去,1101的四位同学都搬出寝室。否则将会发生内存泄漏(memory leak),就是说被分配的内存再也无法使用,1101的人不搬走,其他同学当然用不成这个寝室了。
类型名* point2 = new 类型名;
···;
Delete point2;
对于大型数据,如数组、字符串、结构体,使用new才能真正体会到动态开辟内存的妙处。熟悉数组的朋友应该还记得,创建数组时,一定要明确数组的大小,否则无法成功创建,意味着数组是在编译的时候加入到程序中的,这叫做 静态联编。
而使用new时,我在程序运行时将视具体情况来决定我是否创建数组,并且可以选择其长度,这样的数字称之为 动态数组,此过程被成为 动态联编。 示例: int * points = new int[5]; delete [ ] points;//注意此处一定要有方框[ ],表示我释放的是这整个数组。 使用new和delete时的注意要点: New和delete应该成对出现; 不要用delete来释放不是new开辟的内存; `不要用delete释放同一个内存块两次; `如果用new[ ]为数组分配内存,一定要用delete[ ]来释放内存; `对空指针使用delete是安全的。
int * points = new int[5]; 对于这样一个数组,points指向的是第一个元素的地址,如果要访问第一个元素,那么就可以直接*points。 那么如何访问第二个,第三个元素呢? 把points看成是一个数组!points[1]就是第二个元素,points[0]就是第一个元素,这是因为C++内部也使用指针来处理数组。详细分析会在下一篇博文介绍。 这里先提出一个和数组不一样的地方,对于本例的points来说,points+1后,这个地址对应的就是第二个元素了,points+2对应的就是第三个元素了,这样的加减是合法的。而且加减是以points 对应的类型 所占的字节数 为步长的,即points+1不是说地址的数值只加1,而是加了一个int的长度。 但是如果一个数组int Array[5],我们是不能对数组名Array进行加减的!即Array+1是非法的!