C++精进之路(十二)类和动态内存分配

今天介绍了定义和使用类的许多重要方面。其中的 一些方面是非常微妙甚至很难理解的概念。如果其 中的某些概念对于您来说过于复杂,也不用害怕 —这些问题,对于大多数C++的初学者来说都是很难的。 通常,对于诸如复制构造函数等概念,都是在由于忽略它们而遇到了麻烦后逐步理解的。随着经验越来越丰富,对其理解也将越透彻。
在类构造函数中,可以使用new 为数据分配内存,然后将内存地址赋给类成员。这样,类便可以处理 ⻓度不同的字符串,而不用在类设计时提前固定数组的⻓度。在类构造函数中使用new,也可能在对象过 期时引发问题。如果对象包含成员指针,同时它指向的内存是由new 分配的,则释放用于保存对象的内存 并不会自动释放对象成员指针指向的内存。因此在类构造函数中使用new 类来分配内存时,应在类析构函 数中使用delete 来释放分配的内存。这样,当对象过期时,将自动释放其指针成员指向的内存。
如果对象包含指向new 分配的内存的指针成员,则将一个对象初始化为另一个对象,或将一个对象赋 给另 一个对象时,也会出现问题。在默认情况下,C++逐个对成员进行初始化和赋值,这意味着被初始化 或被赋值的对象的成员将与原始对象完全相同。如果原始对象的成员指向 一个数据块,则副本成员将指向 同一个数据块。当程序最终删除这两个对象时,类的析构函数将试图删除同一个内存数据块两次 ,这将出 错。解决方法是:定义一个特殊的复制构造函数来重新定义初始化,并重载赋值运算符。在上述任何 一种 情况 下,新的定义都将创建指向数据的副本,并使新对象指向这些副本。这样,旧对象和新对象都将引用 独立的、相同的数据,而不会重叠。由于同样的原因,必须定义赋值运算符。对于每 一种情况,最终目的 都是执行深度复制,也就是说,复制实际的数据 ,而不仅仅是复制指向数据的指针。
对象的存储持续性为自动或外部时,在它不再存在时将自动调用其析构函数。如果使用new运算符为对象 分配内存,并将其地址赋给一个指针,则当您将delete用于该指针时将自动为对象调用析构函数 。然而 ,如果 使用定位new运算符(而不是常规new运算符)为类对象分配内存,则必须负责显式地为该对象调用析构函数, 方法是使用指向该对象的指针调用析构函数方法。C++允许在类中包含结构、类和枚举定义。这些嵌套类型的 作用域为整个类,这意味着它们被局限于类中,不会与其他地方定义的同名结构、类和枚举发生冲突。
C++为类构造函数提供了一种可用来初始化数据成员的特 语法。这种语法包括冒号和由逗号分隔的 初始化列表,被放在构造函数参数的右括号后,函数体的左括号之前。每一个初始化器都由被初始化的成 员的名称和包含初始值的括号组成。从概念上来说,这些初始化操作是在对象创建时进行的,此时 函数体 中的语句还没有执行。语法如下:
queue (int qs) : qsize (gs), items (0), front (NULL), rear (NULL) { }|
如果数据成员是非静态const 成员或引用,则必须采用这种格式,但可将C++11新增的类内初始化用 于 非静 态 c o n s t 成 员 。
C ++11 允许类内初始化,即在类定义中进行初始化:
class Queue
{ private:
・・・

Node *front = NULL;

enum{Q_SIZE = 10};

Node *reat = NULL;

const int qsize = Q_SIZE;

}
这与使用成员初始化列表等价。然而,使用成员初始化列表的构造函数将覆盖相应的类内初始化。 与简单的C结构相比,需要注意的类细节要多得多。作为回报,它们的功能也更强。

你可能感兴趣的:(c++)