从C转向C++
- 尽量用const和inline而不是#define
define的缺点:无类型安全,无运行期错误提示。预处理命令,快速。
const 修饰常量,inline函数使用定义式替换调用式但具有参数类型判断。
csdn
- 尽量用
而不用<stdio.h>
命名空间保护,语法标准偏向C++。
- 尽量用new和delete而不用malloc和free
new和delete对构造函数和析构函数的调用,是C++对象构造/析构构成中不可少的步骤。
内存管理
正确得到和有效使用内存
- 尽量使用C++风格的注释
C++风格的注释是指"//"行尾注释法。why? /* */ 不允许嵌套
- 对应的 new 和 delete 要采用相同的形式
申请一个对象数组:new [],而释放一个对象数组:delete [],同样的不同对象的内存申请和释放使用new&delete。
- 析构函数里对指针成员调用 delete
如果写了new一定要有一个delete与之对应,一个对象对资源的申请和释放一般是在构造函数和析构函数中的。
使用智能指针替换普通裸指针。
- 预先准备好内存不够的情况
new 无法申请到足够内存时会抛出异常(std::bad_alloc)
可以通过设置处理函数,控制内存不够时的行为 set_new_handler
一个设计得好的 new-handler 函数必须实现下面功能中的一种:
- 产生更多的可用内存。
- 安装另一个不同的 new-handler 函数。
- 卸除 new-handler。
- 抛出 std::bad_alloc 或从 std::bad_alloc 继承的其他类型的异常。
- 没有返回。
- 写 operator new 和 operator delete 时要遵循常规
- 避免隐藏标准形式的 new
某对象中声明重载operator new(而不定义)会导致标准new在当前类被覆盖。
- 如果写了 operator new 就要同时写 operator delete
一个new一定要有一个delete与之对应,切delete释放的正是new申请的资源。
- 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符
- 尽量使用初始化而不要在构造函数里赋值
初始化对象,而不初始化业务所需的资源。
- 初始化列表中成员列出的顺序和它们在类中声明的顺序相同
类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。
- 确定基类有虚析构函数
否则基类指针无法调用其真实派生对象的析构函数。
- 让 operator=返回*this 的引用
可以通过.而非->继续链式调用。
- 在 operator=中对所有数据成员赋值
不要遗漏,赋值是对整个对象进行赋值,以免有成员未得到正确数值。
- 在 operator=中检查给自己赋值的情况
if(this == &other) 自我赋值会产生多余操作,对某些操作如memcpy等还会导致内存错乱。拥有动态内存的对象中甚至会导致越界等问题。
类和函数:设计与声明
- 争取使类的接口完整并且最小
最好不要有数据成员,尽量把一件事情交给同样的人做。同样的事情涉及的业务,提供所有的接口去完成
- 分清成员函数,非成员函数和友元函数
- 避免 public 接口出现数据成员
导致数据可以直接访问,使用setter和getter
- 尽可能使用 const
使不应该修改的数据可以
- 尽量用“传引用”而不用“传值”
1、性能,2、配合const使用。
- 必须返回一个对象时不要试图返回一个引用
返回引用的对象的生命周期不能小于函数调用处。
- 在函数重载和设定参数缺省值间慎重选择
重载函数声明处的参数缺省值不一定起作用。如果你选用的是基类指针调用,参数缺省值选用的就是基类函数的。
- 避免对指针和数字类型重载
如:void f(int x); 和 void f(string *ps); 在面对调用式:f(0)时冲突。
- 当心潜在的二义性
语义和语法的二义性
- 如果不想使用隐式生成的函数就要显式地禁止它
隐式生成的函数:拷贝构造,赋值运算,默认构造,默认析构。
使用将函数声明为private的方式禁止
- 划分全局名字空间
使用全局匿名命名空间分割
尽量使用命名名称空间
类和函数:实现
- 避免返回内部数据的句柄
- 避免这样的成员函数:其返回值是指向成员的非 const 指针或引用,但成员的访问级比这个函数要低
- 千万不要返回局部对象的引用,也不要返回函数内部用 new 初始化的指针的引用
- 尽可能地推迟变量的定义
- 明智地使用内联
- 将文件间的编译依赖性降至最低
继承和面向对象设计
- 使公有继承体现 "是一个" 的含义
- 区分接口继承和实现继承
- 决不要重新定义继承而来的非虚函数
- 决不要重新定义继承而来的缺省参数值
- 避免 "向下转换" 继承层次
- 通过分层来体现 "有一个" 或 "用...来实现"
- 区分继承和模板
- 明智地使用私有继承
- 明智地使用多继承
- 说你想说的;理解你所说的
- 理解隐式接口和编译期多态
什么是显示接口和运行时多态?
一个显示的接口类,拥有可视的接口和其他约束。
对虚函数的调用具有运行时多态的性质,具体调用的函数取决于this指针的类型。
什么是隐式接口和编译器多态
编译时多态即模板定义处的行为由模板参数传入的类型决定,可以在编译时确定。函数重载也属于编译时多态。
隐式接口及模板定义处的一段表达式对模板类型做出的约束。
杂项
- 弄清 C++在幕后为你所写、所调用的函数
- 宁可编译和链接时出错,也不要运行时出错
- 确保非局部静态对象在使用前被初始化
- 重视编译器警告
- 熟悉标准库
- 提高对 C++的认识