您的位置:首页 > 编程语言 > C语言/C++

Google C++ 编程风格指南

2016-04-05 12:55 429 查看

0. 背景

  每一个C++程序员都知道,C++具有很多强大的语言特性,但这种强大不可避免的导致它的复杂,这种复杂会使得代码更易于出现bug、难于阅读和维护。

  本指南的目的是通过详细阐述在C++编码时要怎样写、不要怎样写来规避其复杂性。这些规则可在允许代码有效使用C++语言特性的同时使其易于管理。

1. 头文件

1.1 #define保护

目的:防止头文件被多重包含
原型:
#ifndef  XXX_XXX_H
#define XXX_XXX_H
...
#endif //XXX_XXX_H


1.2 能依赖声明的就不要依赖定义

  使用前置声明,尽量少.h文件中#include的数量,防止依赖

1.3 内联函数

只有当函数少于10行甚至更少时,才定义为内联函数
函数声明为内联,编译器直接在调用处展开代码,节省成本
析构函数不应该内联,析构函数往往比其表面看起来要长
不要内联那些包含循环、switch语句的函数

除非大多数情况下,循环和switch从不执行

虚函数和递归函数即使被声明为内联函数,实际上他不一定被执行

1.4 函数参数顺序

输入参数在前,输出参数在后
输入参数一般为:值 或 常数引用
输出参数一般为: 非常数指针
好处:

提高可读性和易维护性
对函数参数的堆栈空间有轻微影响

1.5 包含文件的次序

  C库 > C++库 > 其他库的h > 项目内的h

2. 作用域

2.1 命名空间

2.1.1 定义

将全局作用域分为不同的、具名的作用域
防止全局作用域命名冲突

2.1.2 优点

提供了可嵌套的命名轴线
命名轴线功能距离

project1 : : Foo
project2 : : Foo

2.1.3 缺点

  在头文件中使用不具名的空间容易违背C++的唯一定义原则

2.1.4 结论:根据上下文合理使用命名空间

.cc文件允许甚至提倡不具名命名空间

.cc文件包含更多、更复杂的细节
有对其他命名空间中类的引用

.h不要使用不具名命名空间

2.2 嵌套类

不要把嵌套类定义为public,除非他们是接口的一部分
最好将嵌套类的声明置于命名空间中

2.3 非成员函数 / 静态成员函数 / 全局函数

使用命名空间中的非成员函数/静态成员函数
尽量不使用全局函数
更好的方法是:将非、静作为新类的成员
如果单纯为了封装,将不相干的函数放在一起,那还是用命名空间

2.4 局部变量

尽可能置于最小作用域,最好声明变量时就初始化
声明与第一次使用位置越近越好
for(int i = 0; i < 10; ++i)

gcc可正确执行,其他for循环重用第一次循环定义的i

2.5 全局变量

class类型全局变量是被禁止的
内置类型的全局变量是允许的,但使用要三思
多线程代码中非常数全局变量也是被禁止的

3. C++类

3.1 构造函数的职责

职责:只进行没有实际意义的初始化
有意义的数据用init方法实现
缺点:

不易捕获错误,不能使用异常
操作失败会造成对象初始化失败,引起不确定状态

对单参数的构造函数使用C++关键字explicit

单参数构造函数必须是明确的
拷贝构造函数大多数情况也要声明explicit
例外:特意作为其它类的透明包装器的类


禁止使用拷贝构造函数和赋值操作的宏

3.2 结构体和类

  仅当只有数据时使用struct,其他一概使用class

3.3 继承

使用组合通常比使用继承更适宜
如果使用继承,只使用公共继承
所有继承必须是public,想私有继承的话,应采取包含基类实例的方式替代
如果该类有虚函数,其析构函数也应该为虚函数
派生类重定义基类的虚函数时,该派生类函数夜莺声明为virtual函数

3.4 多重继承

应用场景:

  只有至多一个基类中含有实现,其他基类都是纯接口类
优点:

  相比单继承,可复用更多代码

3.5 接口

需满足的条件:

只有纯虚函数和静态函数
没有非静态成员函数
没有定义任何构造函数

必须为之声明虚析构函数

确保接口的所有实现可被正确销毁
此时,该虚析构函数亦为纯虚函数

3.6 操作符重载

  一般情况下不要重载操作符

3.7 存取控制

即get/set函数
存取函数一般内联在头文件中

3.8 Summary

不在构造函数中做太多与逻辑相关的初始化
编译器默认提供的构造函数不会对变量进行初始化
子类重载的虚函数也要声明virtual关键字

4. 智能指针和其他C++特性

智能指针安全第一,方便第二,尽可能局部化

一般用scoped_ptr
任何情况下不用auto_ptr
对stl容器对象,使用shared_ptr

引用形参加上const,否则使用指针形参

避免丑代码:(*ptr)++
对于拷贝构造函数,const是必须的

函数重载的使用要清晰/易读
少用缺省函数参数
禁止使用变长数组和alloca
合理使用友元
慎用异常
使用C++风格的类型转换,除单元测试外不要使用dynamic_cast
能用前置自增/减,不用后置自增/减

前置自增效率更高,后置自增自减要对变量值i进行依次拷贝
如果i是迭代器或者其他非数值类型,一定要用前置

const能用则用,提倡const在前

const变量/函数/参数,会为编译时类型检测增加了一层保障

尽量避免使用宏(c++中)

尽量以内联函数、枚举、常量代替之
不要在头文件中定义宏

整数用0,实数0.0,指正NULL,字符串‘\0’
推荐用sizeof(varname)代替sizeof(type)
只使用Boost中被认可的库

5. 命名约定

不要随意缩写,除非常用约定俗成的缩写
函数名可适当为动词,其他命名使用名词
全部大写+下划线: 宏/枚举
全小写+下划线: 变量(含类变量/结构体变量)、文件、命名空间、存取函数
大小写混合: 函数/类型(类/结构体/枚举)/常量


6.思维导图笔记



原文链接:http://www.jianshu.com/p/9246963118d7
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: