本周学习了带指针类的写法
带指针类中的三个特殊函数
1.拷贝构造函数:又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。
2.拷贝赋值函数:即对“=”重载。由于"="的缺省操作只是将成员变量的值相应复制,而对象内包含指针,将造成不良后果:指针的值被丢弃了,但指针指向的内容并未释放。指针的值被复制了,但指针所指内容并未被复制。所以需要对“=”进行重载。
3.析构函数:析构函数(destructor)与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后”的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
析构函数名应与类名相同,只是在函数名前面加一个位取反符~,例如~string( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显示的析构函数。
堆、栈与内存管理
栈(stack),是存在与某作用域(scope)的一块内存空间(memory space)。例如当你调用函数,函数本身即会形成一个栈用来放置它所接收的参数,以及返回地址。在函数体(function body)内声明的任何变量,其所用的内存块都取自上述栈。
堆(heap或system heap),是指由操作系统提供的一块global内存空间,程序可动态分配(dynamic allocated)从某中获得若干区块(blocks)。
在构造函数中使用new时应注意:
1.如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete
2.new和delete必须相互兼容。new对应于delete,new[]对应于delete []
3.如果有多个构造函数,则必须以相同的方式使用new,要么都带中括号,要么都不带。因为只有一个析构函数,所有的构造函数都必须与它兼容
stack objects的生命周期
class T { } ;
...
{ T t1(1,2); }
t1便是stack object,其生命在作用域(scope)结束之际结束。这种作用域内的object又称为auto object,因为它会被“自动”清理。
static local objects的生命周期
class T { } ;
...
{ static T t2(1,2); }
t2便是static object,其生命在作用域结束之后仍存在,直到整个程序结束。
global objects的生命周期
class T { ... };
...
T t3(1,2);
int main()
{ ... }
t3便是global object,其生命在整个程序结束之后才结束。其可视为一种static object。
heap objects的生命周期
class T {...};
...
{
T* p = new T;
...
delete p;
}
p所指的便是heap object,其生命在它被delete之际结束。
如果没有delete,会出现内存泄漏。