Google C++ Style Guide 阅读笔记

Background

C++是谷歌开源项目的主要使用语言,虽然Google Code 黄了。C++是很强大的语言,以致于增加了其复杂性。为了让代码被其他程序员看懂,减少出bug的可能,所以有了这个谷歌C++风格指导。

Header Files

  • 每个.cc文件都应该与一个.h文件关联,除非是单元测试或者只包含一个main();

The #define Guard

  • 每个头文件都应该避免被重复包含。宏定义可以用PROJECT_PATH_FILE_H_ 的格式。 例如:

  • 在前置声明能够满足的情况下,不要使用#include. 头文件的改变将引起包含它的文件重新编译,因此推荐最小包含原则,尤其是包含其他头文件的头文件。 比如,需要使用File Class 但不需要使用该类的定义声明时,你可以在头文件里使用前置声明 class File 替代 #include "file/base/file.h" 在头文件不获取Foo定义的时候,如何使用Foo Class呢?
    • 使用Foo * 或者 Foo & 声明数据成员。
    • 可以在函数声明里作为定义和返回值。
    • 使用静态数据成员,静态成员是在类外部定义的。 但如果你的类是Foo的子类或者有Foo类型的数据成员,那就包含头文件。不要过度追求减少头文件包含,引起代码复杂度提高和性能消耗。

Inline Functions

  • 10行以上的函数不要内联。
  • 可以使用编译器自动内联。

Function Parameter Ordering

  • 参数顺序: 输入, 输出
  • 输入通常是值或者常量引用

Names and Order of Includes

  • 举例,在dir/foo.h 中:
    1. dir/foo.h
    2. C system files
    3. C++ system files
    4. Other libraries .h files
    5. Your project's .h files

命名空间

  • 在.cc文件中推荐使用无命名的命名空间,但不要在头文件中使用。例如, namespace{ …… } 命名空间应包裹include, 全局定义、声明和其他命名空间的前置声明之后的一切代码:

  • 不要在std命名空间里声明任何东西,也不要前置声明std空间里的类。要声明std中的实体,请包含对应的头文件。

  • 禁止使用 using namespace Foo;将这个命名空间中的名字包含进来,这将污染命名空间。但在.cc文件中的函数、方法或者头文件的Class中使用 using ::foo::bar是可以的。

  • 命名空间的别名: namespace fbz = ::foo::bar::baz;

成员类

  • 好处:只能在当前类中使用,不会污染命名空间
  • 坏处:前置声明的时候将包含整个当前类的声明
  • 不要把成员类设置成public,除非是作为接口的一部分

非成员,静态成员和全局函数

  • 推荐使用命名空间中的非成员函数或者静态成员函数而不是全局函数。

局部变量

  • 尽可能在最小的域中使用局部变量,并且在声明的时候初始化。
  • C++支持在函数的任何位置声明局部变量,但建议越局部越好,越靠近第一次使用越好。
  • 对于 for(int i = 0; i<10; i++)这样的方式,if和while也可以用。

静态和全局变量

  • 静态或全局的Class类型变量是不被允许的,这将导致构造和销毁的模糊不清。
  • 静态存储的对象,包括全局变量,静态变量,静态成员变量和函数静态变量必须是Plain Old Data(POD):ints, chars,floats,pointers 或者它们组成的数组或结构体。
  • 静态变量在类构造和初始化中的顺序是不确定的,所以不要用一个函数的返回值对静态POD初始化。
  • 因为上述原因,在静态变量中应用C 数组替代vector,用const char [] 替代string.
  • 如果一定需要一个Class类型的全局变量,用指针,但不要用智能指针,在main()或者pthread_once()初始化。

构造函数中的工作

  • 通常,构造函数中只对成员变量设置初值,复杂的初始化请使用Init().
    • 信号错误难以处理,禁止使用exceptions.
    • 如果初始化失败,那对象就创建失败了,造成未知状态。
    • 如果在构造函数中调用虚函数,这些调用不能传给子函数的实现。即使现在没有子函数,但对以后的优化造成隐患。
    • 如果其中调用了全局变量,构造将在main()之前进行,可能导致构造函数中的隐式假设失败,比如全局变量初始化失败。
  • 总结:如果你的对象不处理复杂的初始化,请显式地使用Init(),在构造函数里不要调用虚函数,不要抛出错误,不要访问未初始化的全局变量。

默认构造器

  • 必须定义一个默认构造器,如果类中定义了成员变量并且没有其他构造器,如若不然,编译器将为你做这个工作,但可能不够好。
  • 调用new[]构建向量的时候,构造器将总是被调用。
  • 初始化结构体,hold住“不可能”的值,让调试简单。
  • 如果你的类是继承来的且没有添加新的成员变量,那么不需要默认的构造器。

显式构造器

  • 使用 eplicit 避免自动的不符合要求的类型转换。
  • 我们要求单变量的构造器必须是显式的。

复制构造器

  • 只在需要的时候使用,否则用DISALLOW_COPY_AND_ASSIGN关掉该功能。
  • 在创建对象副本的时候复制构造器和赋值操作将被进行。比如用按值传递对象。
  • 多数情况使用指针或者引用就够了。
  • 可以创建CopyFrom()或者Clone()方法。

结构体和类

  • 仅存储数据的对象使用结构体,其他情况都用类。

继承

  • 子类不能重载非虚函数。
  • 具有“is-a”关系的类才能用于继承。
  • 如果类中含有虚函数,那么析构函数也写成虚函数。

接口

  • 具有如下条件的类是一个纯接口:
    • 只有public纯虚方法和静态方法。
    • 没有非静态数据成员。
    • 没有定义任何构造器,如果提供了一个构造器,他必须没有参数且为protected.
    • 如果是子类,它必须继承于具有这些条件的类并且加上Interface前缀。

操作符重载

  • 特殊情况外不要重载操作符。
  • 为了让一些模板函数工作正常,你可能需要重载操作符。
  • 尽量用Equal(),CopyFrom()替代重载操作,如果需要前置定义,避免使用一元操作符operator&。

声明顺序

  • public在private前面,方法在变量前面。
  • public -> prtected ->private,每个部分按如下顺序:
    • Typedef 和枚举
    • 常量(static const 数据成员)
    • 构造函数
    • 析构函数
    • 方法,包含静态方法
    • 数据成员
  • 友元在private中声明,DISALLOW_COPY_AND_ASSIGN在private的末尾。

写短函数

  • 函数超过40行应考虑是否可以拆开。

其他

  • 引用参数必须是const型。输入用const引用,输出用指针。 void Foo(const string &in, string *out);
  • 尽量不使用默认参数。
  • 用static_cast<>,而不要用如 int y = (int)x.
  • 除了登录尽量不用stream,因为没有类型检测,可能会出现不必要的问题。
  • 对于简单类型,没有对象的情况,i++和++i都可以;对于迭代器和模板类型,用前置比较好。
  • 用内联函数替代宏。
    • 在头文件中不要使用宏。
    • 在使用前#define,在用后立即#undef.
  • sizeof(变量名)而不是使用sizeof(类型名),因为类型可能会变。
  • int 用0, reals用0.0,指针用NULL,字符用’\0‘

命名

  • 名字可以长,清晰表达含义是最重要的。
  • 变量用名词,方法用动词。
  • 尽量不要缩写,不要省略字母缩写,如 int err_cnt
  • 类型字母大写,不要下划线
  • 变量小写加下划线分隔字母
  • 成员变量后加_
  • 常量以k开头

格式

  • 每行不要超过80隔字符
  • 用空格不用Tab,可以设置编辑器按tab是释放空格
Google C++ Style Guide 阅读笔记

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax