编程之雅(C++编程准则)

这些编程准则有一些是个人的编程经验,当然,我可没那么多经验,大部分都是各个大师总结出来的,我就是整理一下。

宏观:

将C++视为C、面向对象C++、模版C++、STL C++组成的语言联邦。
任何人不得添加任何东西到STL命名空间
不要轻易忽略编译器的警告
一定程度的使用测试驱动的开发方法
软件实体(类、模块、函数)应该是可扩展的,但是不可修改的
多采用敏捷的设计方法(个体和交互胜过过程和工具、可以工作的软件胜过面面俱到的文档、客户合作胜过合同谈判、响应变化胜过遵循计划)
经常性的交付可以工作的软件,交付的时间间隔越短越好
在整个项目开发期间,业务人员和开发人员必须天天都在一起工作
围绕被激励起来的个人来构建项目
在团队内部,多进行面对面的交流
提倡可持续的开发速度
使要构造的系统最简单(不要设计不需要的功能,不要过分设计)
最好的架构、需求和设计出自于自组织团队
每隔一段时间,团队会在如何才能更有效的工作方面进行反省,然后相应的对自己的行为进行调整
结对编程是一种比较好的选择
不能容忍重复的代码
持续的对代码进行重构
要做计划游戏
高层模块不应该依赖于底层模块。二者都应该依赖于抽象
尽可能的保证:抽象不应该依赖于细节,细节应该依赖于抽象(任何变量都不应该持有一个指向具体类的指针或引用;任何类都不应该从具体类派生;任何方法都不应该覆写它的任何基类中已经实现了的方法)
每个编程单元尽可能的向使用者提供使用承诺:例如资源回收保证、数据一致性保证、无异常保证
尽可能的在程序中处理所有可能的异常,而且尽可能的精细。(try...catch)
应该让程序体面的退出:在出现非计划内问题时自动产生dump文件。(利用SetUnhandledExceptionFilter调用MiniDumpWriteDump)
要先设计好类,建好各个类的文件,才能写代码。
用pragma once代替h文件头

类:
让接口容易被正确使用,不易被误用
设计class犹如设计type
将成员变量声明为private
尽量不要让类支持隐式类型转换
friend成员函数是类接口的一种表现方式,但能避免使用就尽量避免
避免使用handles指向对象内部成分
慎重使用inline(小函数的确该用inline,但是考虑到inline函数无法调试,所以应谨慎)
确定public继承表现出is-a关系(即Liskov替换原则,永远可以用派生类取代基类)
避免覆盖继承而来的名称(基类函数重载,派生不重载,则其他覆盖;派生重载基类函数,则基类函数覆盖;变量也可以覆盖)
区别接口继承和实现继承(纯接口(virtual=0),接口+朴素实现(virtual=0+实现),接口+强制实现(non-virtual),以上为public继承,private继承全部是为了继承实现,而不继承接口)
根据上一条,只要出现virtual,就尽可能让它=0(成虚基类)
根据上上条,派生类不应该覆写non-virtual函数
绝不重新定义继承而来的缺省参数值
private继承意味着继承实现,是composition,实现的是has-a逻辑。protected继承尽量少用。两种继承在设计层面完全没有意义,只是实现层面的代码重用。
凡是独立的对象都必须有非0大小(空对象会安插一个char)
一个类只负责一件事
一个类只提供一种内聚的接口(不应该让用户依赖于他们不使用的方法)
类内部的类型定义尽量放在public,否则不能作为返回值
类中的大属性都应该用智能指针(或返回STL时应使用move语意)
凡是类内私有变量加m前缀,凡事类似私有仿函数,加or后缀
静态成员初始化函数用静态类替代,可以顺便用个functor

 


四大函数(构造函数、拷贝构造、赋值、析构)

若有多态继承体系,基类析构函数尽量声明为virtual
如果类内new了对象,并且该类负责delete,则必须要定义拷贝构造函数和赋值操作符。
若不想使用编译器自动生成的函数,就该默认拒绝(将其声明在private或protected)
别让异常逃离析构函数,C++不喜欢析构函数吐出异常
绝不在构造函数或析构函数中调用virtual函数(当然其他函数调用virtual可以实现template method等有趣的模式)
拷贝函数应该确保拷贝了对象内所有成员和基类部分
不要以某个拷贝函数去实现另外一个拷贝函数(一个是copy函数,一个是copy assignment函数),应该把共同部分放在第三个独立函数

 

函数:

尽量将函数参数声明为const
另operator =返回一个*this的引用,并且在operator =中处理自我赋值
函数参数的构造顺序不确定,所以不要在函数参数中执行new操作,或将多个函数参数都用函数来表示(否则若一个发生异常,其他有可能不会执行)。
尽量用传递const 引用代替传值
non-member,none-friend函数有封装性好,跨类型操作等能力,因此在需要的时候没有必要局限于把函数全部放到类里的传统规则。
若所有参数都需要类型转换,请为此采用non-memeber函数(典型的是双目操作符重载)
凡是需要对指针参数做提领操作,都需要检查是否为BULL
发布版程序维持程序的勉强工作比crash更好;debug版让程序尽量crash。(例如对NULL指针的提领)

 


代码布局:

头文件尽量不要包含头文件,尽可能的用前置声明。
类的声明和实现应该分开(template没有export可以用时得谨慎)
若必须要在同一文件中交叉引用定义,则可考虑类中类
所有类都该有自己的名称空间。


杂项:

尽可能用const enum inline 替换#define
尽可能使用const
确定对象调用前已先被初始化。(包括基本对象、类对象、类成员)
使用引用计数型智慧指针时,应该注意RCSPs无法打破环状引用
成员使用new和delete时应采用相同的形式
尽可能延后变量定义式的出现时间(Singleton)
尽可能少用转型操作,(reinterpret_cast,static_cast,const_cast太危险,dynamic_cast效率太低),但如果要转型,尽量用C++的*cast转型关键字。
输入流的getline尽量用全局getline函数。(可以用string)
不用临时变量,方便调试
轻量级对象应尽量多用临时对象
引用只用于立即处理,若需要长久保存,则得用堆
数值类型转化要用显式,尽量避免用隐式

模版
大项目中,尽量不要使用显式实例化
尽量使用包含模型组织模版代码
模版函数所有重载版本的声明都应位于被调用位置之前
模版函数的重载应只改变参数数或显式指定模版参数
模版参数两个>之间要求有空格
不得不用template不能采用分离模型时,对成员模版函数的特化必须在类外部用inline特化,否则会有重复定义问题。
模版构造函数不能在类内定义,必须要在类外定义。如果有模版构造函数的需求,尽量全部在类体外const inline定义(支持export的话可以考虑)
资源管理:
一旦使用了资源,必须归还,并且谁用谁归还(包括内存、文件描述器、互斥锁、图形界面中的字型和笔刷、数据库连接、网络socket)
用对象来管理资源
资源取得的时机便是初始化的时机。
在资源管理类中小心coping行为
在资源管理类中提供对原始资源的访问
RAII

 

 

 

STL:

可以用for_each来避免显示使用迭代器
std内部是深拷贝

设计模式:

全局唯一对象尽量用Singleton,而不是用static
可以用non-virtual Interface的方式实现template method
用tr1::funtion实现strategy


---------------------
作者:broler
来源:CSDN
原文:https://blog.csdn.net/ljy1988123/article/details/7578263
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-02-23 16:24  lemaden  阅读(164)  评论(0编辑  收藏  举报