google 代码风格笔记

google 代码风格笔记

yolocai 2017.8.3

1. 所有按引用传递的参数必须加上 const.

`void Foo(const string &in, string *out);`

2. 函数重载

如果您打算重载一个函数, 可以试试改在函数名里加上参数信息。例如,用 AppendString() 和 AppendInt() 等, 而不是一口气重载多个 Append().

3. 不同整形和无符号数据类型

4. 使用宏时要非常谨慎, 尽量以内联函数, 枚举和常量代替之.

值得庆幸的是, C++ 中, 宏不像在 C 中那么必不可少. 以往用宏展开性能关键的代码, 现在可以用内联函数替代. 用宏表示常量可被 const 变量代替. 用宏 “缩写” 长变量名可被引用代替. 用宏进行条件编译… 这个, 千万别这么做, 会令测试更加痛苦 (#define 防止头文件重包含当然是个特例).

下面给出的用法模式可以避免使用宏带来的问题; 如果你要宏, 尽可能遵守:
+ 不要在 .h 文件中定义宏.
+ 在马上要使用时才进行 #define, 使用后要立即 #undef.
+ 不要只是对已经存在的宏使用#undef,选择一个不会冲突的名称;
+ 不要试图使用展开后会导致 C++ 构造不稳定的宏, 不然也至少要附上文档说明其行为.
+ 不要用 ## 处理函数,类和变量的名字。

5. 你可以用列表初始化。

```
// Vector 接收了一个初始化列表。
vector v{"foo", "bar"};

// 不考虑细节上的微妙差别,大致上相同。
// 您可以任选其一。
vector v = {"foo", "bar"};

// 可以配合 new 一起用。
auto p = new vector{"foo", "bar"};

// map 接收了一些 pair, 列表初始化大显神威。
map m = {{1, "one"}, {2, "2"}};

// 初始化列表也可以用在返回类型上的隐式转换。
vector test_function() { return {1, 2, 3}; }

// 初始化列表可迭代。
for (int i : {-1, -2, -3}) {}

// 在函数调用里用列表初始化。
void TestFunction2(vector v) {}
TestFunction2({1, 2, 3});
```

6. 只有当函数只有 10 行甚至更少时才将其定义为内联函数.

7. #include 的路径及顺序

使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: 相关头文件, C 库, C++ 库, 其他库的 .h, 本项目内的 .h.

8. 将函数变量尽可能置于最小作用域内, 并在变量声明时进行初始化.

int i;
i = f(); // 坏——初始化和声明分离
int j = g(); // 好——初始化时声明

vector<int> v;
v.push_back(1); // 用花括号初始化更好
v.push_back(2);

vector<int> v = {1, 2}; // 好——v 一开始就初始化

如果变量是一个对象, 每次进入作用域都要调用其构造函数, 每次退出作用域都要调用其析构函数.

// 低效的实现
for (int i = 0; i < 1000000; ++i) {
    Foo f;                  // 构造函数和析构函数分别调用 1000000 次!
    f.DoSomething(i);
}

Foo f;                      // 构造函数和析构函数只调用 1 次
for (int i = 0; i < 1000000; ++i) {
    f.DoSomething(i);
}

9. 隐式类型转换

不要定义隐式类型转换. 对于转换运算符和单参数构造函数, 请使用 explicit 关键字.

class String{
    public:
    explicit String(int n){};
    String(const char *p){};
};

void Func(Foo f){};
int main(){
     //String s1 = 'a'; //错误:不能做隐式char->String转换
    String s2(10);   //可以:调用explicit String(int n);
    String s3 = String(10);//可以:调用explicit String(int n);再调用默认的复制构造函数
    String s4 = "Brian"; //可以:隐式转换调用String(const char *p);再调用默认的复制构造函数
    String s5("Fawlty"); //可以:正常调用String(const char *p);
}

10. 结构体 VS. 类

仅当只有数据成员时使用 struct, 其它一概使用 class.

11. 继承

所有继承必须是 public 的. 如果你想使用私有继承, 你应该替换成把基类的实例作为成员对象的方式.

不要过度使用实现继承. 组合常常更合适一些. 尽量做到只在 “是一个” (“is-a”, 其他 “has-a” 情况下请使用组合) 的情况下使用继承: 如果 Bar 的确 “是一种” Foo, Bar 才能继承 Foo.

必要的话, 析构函数声明为 virtual. 如果你的类有虚函数, 则析构函数也应该为虚函数.

对于可能被子类访问的成员函数, 不要过度使用 protected 关键字. 注意, 数据成员都必须是 私有的.

对于重载的虚函数或虚析构函数, 使用 override, 或 (较不常用的) final 关键字显式地进行标记. 较早 (早于 C++11) 的代码可能会使用 virtual 关键字作为不得已的选项. 因此, 在声明重载时, 请使用 override, final 或 virtual 的其中之一进行标记. 标记为 override 或 final 的析构函数如果不是对基类虚函数的重载的话, 编译会报错, 这有助于捕获常见的错误. 这些标记起到了文档的作用, 因为如果省略这些关键字, 代码阅读者不得不检查所有父类, 以判断该函数是否是虚函数.

12. 声明顺序

类定义一般应以 public: 开始, 后跟 protected:, 最后是 private:. 省略空部分.

13. 参数顺序

函数的参数顺序为: 输入参数在先, 后跟输出参数.

14. 命名规则

通用命名规则

int price_count_reader;    // 无缩写
int num_errors;            // "num" 是一个常见的写法
int num_dns_connections;   // 人人都知道 "DNS" 是什么
int n;                     // 毫无意义.
int nerr;                  // 含糊不清的缩写.
int n_comp_conns;          // 含糊不清的缩写.
int wgc_connections;       // 只有贵团队知道是什么意思.
int pc_reader;             // "pc" 有太多可能的解释了.
int cstmr_id;              // 删减了若干字母.

文件命名

文件名要全部小写, 可以包含下划线 () 或连字符 (-), 依照项目的约定. 如果没有约定, 那么 “” 更好.

类型命名

类型名称的每个单词首字母均大写, 不包含下划线: MyExcitingClass, MyExcitingEnum.

变量命名

变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.

函数命名

常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配: MyExcitingFunction(),
MyExcitingMethod(),
my_exciting_member_variable(), set_my_exciting_member_variable().

你可能感兴趣的:(项目相关,编辑器)