powered by github 总结
让自己习惯c++/培养良好的c++习惯??
视c++为语言联邦??尽量以const, enum, inline 替换#define预处理器
尽可能使用const
确定对象在被使用前就已经初始化了(尽可能不要定义变量后没有初始化)
谏言
- 了解c++默默编写了哪些函数?
-
empty class
编译器会为其声明哪些东西: 一个copy构造函数, 一个copy assinment 操作符, 一个析构函数, 默认构造函数. 都是public 和 inline的. (默认构造/析构函数, 拷贝构造函数, 赋值运算符, 取址运算符, 取址运算符const)Empty(){}
Empty(const Empty&){}
~Empty(){}
A& operator=(const A&){}
A* operator&(){}
const A* operator&()const{}
如果不想使用编译器自动生成的函数, 应当明显拒绝
为多态基类声明virtual 析构函数
别让异常逃离析构函数??
绝对不在构造和析构的过程中调用virtual函数(因为类调用从不????)
令
operator=
返回一个reference to *this
在
operator=
中处理 "自我赋值"赋值对象时应确保复制"对象内的所有成员变量" 及 "所有 base class 成分"
以对象管理资源, 资源在构造函数获取, 析构函数释放, 建议使用智能指针, 取得即初始化, RAII
在资源管理类中小心copy行为(普遍的RAII class copy 行为是: 抑制copy, 引用计数, 深度拷贝, 转移资源所有权啊之类的) ??
成对使用new和delete
以独立语句将new的对象存储于智能指针
让接口容易被正确使用, 不易被误用 促进接口正常使用的办法: 接口一致性, 内置类型的行为兼容, 阻止误用的办法: 建立新类型, 限制类型上的操作, 约束对象, 消除客户的资源管理责任
设计class犹如设计type, 需要考虑:
对象创建, 销毁, 初始化, 赋值, 值传递, 合法值, 继承关系, 转换, 一般化
等在资源管理类中, 一般而言显示转换会比较安全
成对使用new和delete时要采用相同的形式, 比如new中使用[], 则delete[], new中不使用[], 则使用delete
以独立的语句将new的对象存储于智能指针中. 不然可能会被编译器一起优化, 导致难以察觉的资源泄漏. 发生异常时可能会导致资源泄漏.
让接口容易被正确使用, 不易被误用. 促使正确使用的方法: 接口一致性, 内置类型的行为兼容; 防止被误用的方法: 建立新的类型, 限制类型上的操作, 约束对象值, 消除客户的资源管理责任.
设计class要考虑很多东西: 对象创建, 销毁, 初始化, 赋值, 值传递, 合法值, 继承关系, 转换, 一般化等
用pass-by-reference-to-const 替换 pass-by-value 就是传参, 尽量采用 const &的方法, 避免多余的拷贝构造和
对象切割(派生类在拷贝构造时会损失派生部分的内容, 表现为基类的特性)
必须返回对象时, 不要返回pointer和reference, 注意不要返回一个临时对象.
将成员变量声明为private, 封装性和一致性, 对读写权限的精确控制
宁以 non-member, non-friend 替换 member函数 (可以增加封装性, 包裹弹性, 机能扩充性)
若所有参数 (包括被this指针所指向的隐喻参数) 都要类型转换, 请为此采用non-member 函数
考虑写一个不抛异常的swap函数
尽可能延后变量定义式的出现时间 (可以增加程序清晰度并改善程序效率)
尽量少做类型转换的动作, const_static<T expression>, dynamic_cast <T expression>, static_cast<T expression>, reinterpret_cast<T expression>
避免使用handles (包括 引用, 指针, 迭代器) 去指向对象内容 (增加封装性)
为"异常安全"而努力是值得的, 及时发送异常也不会泄漏资源,或者允许任何数据损坏, 分为三种可能的保证: 基本型, 强烈型, 不抛异常型
透彻了解inlining的里里外外外, inline 内联函数, 取决于编译器, 大部分编译器拒绝太过复杂的函数作为内联函数来使用. 容易导致代码膨胀, 且内联函数无法随着程序库的升级而升级.
将文件的编译之间的依赖关系降到最低.如果可以, 尽量以class声明替换class 定义式, 为声明和定义提供不同的头文件.
确定你的public 继承is-a 关系
??
避免遮掩继承而来的名字, 可以使用using 声明式或转接函数
??
区分接口继承和实现的继承, 在public继承之下, derived class 总是继承 base class 的接口, pure virtual 函数只具体指定接口继承, 非纯 impure virtual 函数具体指定接口继承及缺省实现继承
??
考虑virtual 函数以外的其他选择, 将virtual 函数替换为 "函数指针成员变量", 将继承体系内的vitrual函数替换为另外一个继承体系内的virtual函数
绝对不重新定义继承而来的non-virtual 函数
绝对不重新定义继承而来的缺省参数值, 因为缺省参数值是静态绑定的, 而virtual 函数却是动态绑定的.
通过复合塑模 has-a 或 "根据某物实现出"; 在实现域, 复合意味着is-implemented-in-terms-of
明智而谨慎地使用private继承. 尽可能使用复合, 当derived class 需要访问protected base class成员, 或需要重新定义继承而来的virtual 函数, 或需要 empty base 最优化时, 才使用private继承
明智而谨慎地使用多重继承, 多继承比单一继承要复杂, 可能导致新的歧义性, 以及对virtual 继承的需要, 但正确的用途也是有的, 比如 "public 继承某个 interface class" 和 "private 继承某个协助实现的 class"; virtual 继承可以解决多继承下的菱形继承的二义性问题, 但会增加大小, 速度, 初始化赋值的复杂度等成本.
了解隐式接口和编译器多态. (class 和 templates 都支持接口 interface 和多态); class的接口是以签名为中心的显式的explicit,多态则是通过virtual 函数发生于运行期; template的接口是奠基于有效表达式的隐式implicit, 多态则是通过template具现化和函数重载解析发生于编译期.
[模板]
了解typename 的双重意义, 声明template 类型参数是, 前缀关键字 class 和 typename 的意义完全相同; 请使用关键字 typename 标识嵌套从属类型名称, 但不得在基类列表或成员初值列内以它作为base class 修饰符.[模板]
学习处理模板化基类的名称.[模板]
运用成员函数函数模板去接收所有兼容类型生成 可接受所有兼容类型的函数.[模板]
运用成员函数模板接收所有兼容类型[模板]
需要类型转换时请为模板定义非成员函数[模板]
请使用 traits classes 表现类型信息[模板]
认识template元编程, 可以将工作由运行期转移到编译期, 可以实现早期错误侦测和更高的执行效率.[new-delete]
了解 new-handler的行为, nothrow new是一个颇具局限的工具, 因为它只使用于内存分配, 后续的构造函数调用还是可能抛出异常的.[new-delete]
了解new 和 delete的合理替换时机, 为了检测运用错误, 收集动态分配内存之使用统计信息, 增加分配和归还速度, 降低缺省内存管理器带来的空间额外开销, 弥补缺省分配器中的非最佳齐位, 增加相关对象......... 太复杂和绕了[new-delete]
编写new和delete, 需要固守常规, 涵盖无穷循环, 在其中尝试分配内存, 如果没有办法满足内存需求, 调用new-handler, 有能力处理0 bytes申请.[new-delete]
写了placement new 也要写 palcement delete不要忽视编译器的警告
让自己熟悉标准程序库
让自己熟悉boost库, 增加一个 poco库