5.了解c++默默编写并调用哪些函数
空类中
如果自己没有声明,编译器就会声明一个default构造函数,一个copy构造函数,一个copy assignment操作符,一个析构函数
不能生成operator = 的条件
1.内含reference成员和内含const成员(c++不允许reference和const改变)
2.基类copy assignment为private
6.若不想使用编译器自动生成的函数,就该明确拒绝
拒绝的方法:
●将成员函数声明为private而且故意不实现它们
●继承专门为了阻止copying动作设计的base class,不过可能造成多重继承
7.为多态基类声明virtual析构函数
工厂函数:返回一个base class指针,指向新动态分配的derived class对象
原因:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义
解决:声明virtual析构函数,不过不作为base class不用声明virtual析构函数
规律:多态性质的base class声明virtual析构函数。只有当class内含至少一个virtual函数,才为它声明virtual析构函数
pure virtual析构函数:导致抽象class,不能实体化(不能创建对象),总是作为base class,必须为纯虚析构提供定义
8.别让异常逃离析构函数(析构函数不要吐出异常)
原因:析构函数如果销毁多个对象,遇到异常会继续销毁,遇到两个异常时,程序会导致不明确行为,c++不喜欢析构函数吐出异常
解决:
不太好的两种办法
较好的策略:重新设计接口,使客户有机会对可能出现的问题作出反应
9.绝不在构造和析构过程中调用virtual函数
准则:在构造和析构期间不要调用virtual函数,因为这类调用停留在基类,调用基类的virtual函数。
正确做法:令派生类将必要的构造信息向上传递至基类构造函数,例子见书
c++这么做的原因:当派生类构造开始前,不能调用派生类的函数,因为函数几乎必然调用local成员变量,而那些成员尚未初始化,所以调用基类的函数(即对象在派生类构造函数开始前不会成为派生类对象)
10.令operator= / +=等 返回一个reference to *this
连锁赋值:x = y = z = 15
即 x = (y = (z = 15))
15先赋值给z,更新后的z赋值给y ……
赋值操作符返回return *this;
方便连锁赋值
11.在operator= 中处理自我赋值
自我赋值:
//明显的
a = a;
//潜在的
a[i] = a[j]; //i可能和j相等
*px = *py; //可能指向同一个东西
自我赋值、异常的安全性
●自我赋值不安全,异常不安全:
●自我赋值安全,异常不安全:new导致异常,会有一个指针指向被删除的Bitmap(new那句话没执行,而this的pb被删除了)
●两者都安全:在复制pb所指对象之前别删除pb,这样如果new抛出异常,pb保持原状
copy and swap技术(常见也好的办法)
用上面的,下面的虽然简单但不太清晰
12.复制对象时勿忘其每一个成分
注意:自己声明自己的copying函数,编译器就会被冒犯,在你的代码出错时不告诉你。
解决:为class添加一个成员变量,必须同时修改copying函数(以及所有构造函数)
derived class撰写copying函数
注意:
●也要复制器base class成分,不然那些成分就会缺省初始化
●base class成分往往是private,无法直接访问,应该让derived class的copying函数调用响应的base class函数
copy与copy assignment不能互相调用
原因:构造函数用来初始化对象,而assignment操作符只能用于已初始化对象身上
解决:为了消除重复代码,建立一个新的成员函数给两者调用,往往是private且命名为init