第12章,类和动态内存的分配
12.1动态内存和类
12.1.1 复习范例和静态类成员
1,不能在类声明中初始化静态成员遍历变量,这是因为声明描述了如何分配内存,但是并不分配内存。同时对于静态类成员,可以在类声明之外使用单独的语句来进行初始化。但是如果静态成员是整型或枚举型const,则可以在类声明中初始化。
2,在构造函数中使用new来分配内存时,必须在相应析构函数中使用delete来释放内存。 如果使用new[](包括中括号)来分配内存,则应使用delete[](包括中括号)来释放内存。
3,注意如下代码:
StringBad sailor = sports; 等同于:
StringBad sailor =
StringBad(sports);因此相应的构造函数原型应该如下:
StringBad (const
StringBad &);
也就是说,当你使用一个对象来初始化另一个对象时,编译器将自动生成上述构造函数(称为复制构造函数,因为它创建对象的一个副本)。
12.1.2隐式成员函数
1,C++自动提供了下面这些成员函数:
l 默认构造函数,如果没有定义构造函数。
l 复制构造函数,如果没有定义。
l 复制操作符,如果没有定义。
l 默认析构函数,如果没有定义。
l 地址操作符,如果没有定义
更准确的说,编译器将生成最后四个函数的定义。假如将一个对象赋值给另一个对象,编译器将提供赋值操作符的定义。
2,复制构造函数
1,复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中,而不是常规的复制过程中。原型如下:
Class_name (const Class_name &);
2,何时调用复制构造函数,下面四种声明都将调用:
l StringBad ditto(motto);
l StringBad metoo = motto;
l StringBad also = StringBad(motto);
l StringBad *pStringBad = new StringBad(motto);
其中中间的两种声明可能会使用复制构站函数直接创建metoo和also,也肯能使用
复制构造函数生成一个临时对象,在将临时对象的内容赋给metoo和also。
最后一个声明使用motto初始化一个匿名对象,并将新对象的地址赋值给pstring指针。
每当程序生成了对象副本时,编译器都将使用复制构造函数。具体说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数。
3,复制构站函数的功能
l 默认的复制构造函数将一个一个的复制非静态成员(成员复制也成为浅复制),复制的是成员的值。
l 注意默认是按值复制的。也就是说如果两个指针按值赋值得话,指向的是同一个内存位置。所以一定要注意,那个内存位置会不会被释放,然后又被其中一个重新调用。如果要避免,可以使用显式的复制构站函数来解决这个问题。可达到深度复制的目的。
4,赋值操作符
l C++允许类对象赋值,这是通过自动为类冲在赋值操作符实现的。这种操作符的原型如下:
Class_name & Class_name :: operator = (const Class_name &);
它接受并返回一个指向类对象的引用。
l 将已有对象赋值给另一个对象时,将使用重载的赋值操作符。
l 赋值操作符的隐式实现也对成员进行一个一个的复制。如果成员本身就是类对象,则程序将使用为这个类定义的赋值操作符来复制该成员,但对静态数据成员不影响。
l 也是一个浅复制,所以有可能导致不同对象指向同一个地址。为避免,我们应使用提供赋值操作符定义。达到深度复制的目的。
1, 在谈new和delete
在构造函数中通过new地址,在析构函数中通过delete
2, 在以下情况中析构函数将被调用
l 如果对象是动态变量,则当执行完定义该对象的程序块时,将调用该对象的析构函数。
l 如果对象是静态变量(外部,静态,静态外部或来自名称空间),则在程序结束时将调用对象的析构函数。
l 如果对象是用new创建的,则仅当你显式使用delete删除对象是,其析构函数才会被调用。