1.如果定义了一个有参数的构造函数,要么没有默认构造函数,要么就需要显示的定义一个.
2.class A{..};
A ma;//用默认构造函数定义ma
A mb();//这不是构造对象,这是一个返回值为A类型的函数声明.
3.默认构造函数的重要性:由于在定义类对象的数组时,不能调用带参数的构造函数,这时就只能调用默认构造函数.
4.const类对象只能调用const成员函数,但是对于构造函数例外.因为const对象的常量性在构造完所有成员后才出现,而在开始析构前失去.
5.隐式转换:单个参数的构造函数(或者除了第一个参数,其他参数都有默认值),被当做无意识的类型转换符,例如A(int _m){};//类A的某个构造函数,在某些情况下,可以把int型转换为A型.
6.拷贝构造函数:用一个类对象初始化另一个类对象被称为默认按成员初始化,当对象申请了系统资源时,这样做往往会出问题,而定义拷贝构造函数可以解决这个问题.拷贝构造函数的参数往往是const类型,并且要是一个引用(如果不是引用类型,那么在给传递参数时,会出现无限递归地调用拷贝构造函数的问题)
14.3析构函数
1.析构函数用~开头,没有返回类型,没有参数,所以也不能重载.
2.显示调用析构函数:这种情况一般都是与定位new操作相结合,结束对象,但是对象占用的底层资源并不释放.例如
char *arena = new char[sizeof Image];//申请一块堆内存,大小与类Image相等
Image *ptr=new(arena) Image("A");//注意,没有申请新内存!只是在arena的地址存储了一个Image对象A
//如果我们想在arena位置存放另一个Image对象,初始化为B
/*delete ptr*/ //错误:这样会释放底层的arena指向的内存
ptr->~Image();//显式调用析构函数,这里的析构函数内容往往是把Image对象存储到磁盘中
ptr = new(arena) Image("B");//在arena位置存储新对象,如果没有上一步,直接这么做,会覆盖原来内容.
14.4类对象数组和vector
1.对于在堆上申请的一组类对象元素,我们无法用显式的值来初始化,所以类必须提供默认构造函数,或者补提供构造函数.
account* pact = new account[10];
析构:
delete pact;//error:系统无法识别pact是一个指向类对象数组的指针,所以只会对第一个元素执行析构
//也就是说,pact所占内存会被释放,但是后面的元素都没有执行析构
delete [] pact;//正确的写法,对每个数组元素都执行析构函数
2.类对象数组初始化
3.堆数组的初始化和析构:堆数组的初始化,实际就是先申请未经构造处理的毛坯内存,然后使用定位new操作在每个元素的偏离位置进行对象构造;析构时,也不能单纯使用delete [] pa的写法,要依次调用析构函数,然后再delete毛坯内存指针.
14.5成员初始化表
1.成员初始化表初始化顺序按成员在类体中声明的顺序进行
2.const成员和引用成员初始化只能在成员初始化列表中进行,不能放在构造函数内.
3.初始化列表隐式时(就是没有),会调用各成员的默认构造方法,所以如果有成员是类对象,一般都尽量放在初始化列表构造,避免在函数体内再次调用其构造函数.
14.7按成员赋值
1.定义一个显式的赋值操作符函数,函数中要防止对象对自身赋值.因为赋值之前,需要先释放对象自身资源,如果不判断是自身赋值,释放之后就无法进行后续操作.
阅读(1514) | 评论(0) | 转发(0) |