码迷,mamicode.com
首页 > 编程语言 > 详细

学习笔记:google c++ 编程风格指南

时间:2017-10-19 11:07:21      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:封装   pre   增强   streams   延伸   span   函数返回值   rtu   友元   

目录:
一、头文件.................................................
二、作用域.................................................
三、C++类.................................................
四、智能指针和其他C++特性....................
五、命名约定.............................................
六、代码注释.............................................
七、格式....................................................

一、头文件 
1.#define保护
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_
2.头文件依赖 
当一个头文件被包含的同时也引入了一项新的依赖,只要该头文件被修改,代码就要重新编译。
因此尽量少的包含头文件,使用前置申明可以减少头文件包含,如:
头文件中用到类 File,但不需要访问File的声明,则头文件中只需前置声明 class File;无需#include "file/base/file.h"
使用指针成员*Foo替代对象成员Foo,这样无需访问类的定义。
能依赖声明的就不要依赖定义。
3.内联函数
只有当函数只有10行甚至更少时才会将其定义为内联函数( inline function)。
当函数体比较小的时候,内联该函数可以令目标代码更加高效。对于存取函数以及其他一些比较短的关键执行函数。
4.-inl.h文件
复杂的内联函数的定义,应放在后缀名为-inl.h 的头文件中。
-inl.h文件还可用于函数模板的定义,从而使得模板定义可读性增强。
-inl.h和其他头文件一样,也需要#define 保护。
5.函数参数顺序 
定义函数时,参数顺序为:输入参数在前,输出参数在后
输入参数一般传值或常数引用(const references),输出参数或输入/输出参数为非常数指针( non-const pointers)。
6.包含文件的名称及次序 
次序如下:C库、C++库、其他库的.h、项目内的.h
C 系统文件
C++系统文件
其他库头文件
本项目内头文件

二、作用域
1.命名空间 
命名空间将全局作用域细分为不同的、具名的作用域,可有效防止全局作用域的命名冲突。
*.cc文件中可以使用不具名命名空间;
*.h文件中只能使用具名命名空间,不能使用不具名命名空间;
最好不要使用 using指示符,以保证命名空间下的所有名称都可以正常使用。
2.嵌套类 
可以在一个类中定义另一个类,嵌套类也称成员类。
当嵌套(成员)类只在被嵌套类( enclosing class)中使用时很有用,将其置于被嵌套类作用域作
为被嵌套类的成员不会污染其他作用域同名类。class Foo {
private:
// Bar 是嵌套在 Foo 中的成员类
class Bar {
...
  };
};
3.非成员函数、静态成员函数和全局函数
使用命名空间中的非成员函数或静态成员函数,尽量不要使用全局函数。
4.局部变量
将函数变量尽可能置于最小作用域内,在声明变量时将其初始化。
如果变量是一个对象,每次进入作用域都要调用其构造函数,每次退出作用域都要调用其析构函数,类似变量放到循环作用域外面声明要高效的多
5.全局变量
class类型的全局变量是被禁止的,内建类型的全局变量是允许的,当然多线程代码中非常数全局变量也是
被禁止的。永远不要使用函数返回值初始化全局变量。

三、C++类  
1. 构造函数的职责
构造函数中只进行那些没有实际意义的初始化,如果对象需要有意义的初始化,考虑使用另外的Init()方法并(或)增加一个成员标
记用于指示对象是否已经初始化成功。
2. 默认构造函数
如果一个类定义了若干成员变量又没有其他构造函数,需要定义一个默认构造函数(没有参数),否则编译器将自动生成默认构造函数。
3. 明确的构造函数
对单参数构造函数使用 C++关键字 explicit。
只有一个参数的构造函数可被用于转换(隐式转换生成一个新的对象),为避免构造函数被调用造成隐式转换,可以将其声明
为explicit。
4. 拷贝构造函数
仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数;不需要拷贝时应使用DISALLOW_COPY_AND_ASSIGN。
// 禁止使用拷贝构造函数和赋值操作的宏
// 应在类的 private:中使用
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
class Foo {
public:
Foo(int f);
~Foo();
private:
DISALLOW_COPY_AND_ASSIGN(Foo);
};
绝大多数情况下都应使用DISALLOW_COPY_AND_ASSIGN,如果类确实需要可拷贝,应在该类的头文件中说明原由,并适当定义拷贝构造函数和赋值操作,注意在operator=中检测自赋值(self-assignment)情况。
5.结构体和类
仅当只有数据时使用struct,其它一概使用class。
6.继承  
使用组合通常比使用继承更适宜,如果使用继承的话,只使用公共继承。
实现继承通过原封不动的重用基类代码减少了代码量,接口继承可用于程序上增强类的特定API的功能。
限定仅在子类访问的成员函数为protected,需要注意的是数据成员应始终为私有
当重定义派生的虚函数时,在派生类中明确声明其为virtual。根本原因:如果遗漏virtual,阅读者需要检索类的所有祖先以确定该函数是否为虚函数。
7.多重继承
只有当最多一个基类中含有实现,其他基类都是以Interface为后缀的纯接口类时才会使用多重继承。
多重继承允许子类拥有多个基类,要将作为纯接口的基类和具有实现的基类区别开来。
8.接口
纯接口:
1) 只有纯虚函数("=0")和静态函数(下文提到的析构函数除外);
2) 没有非静态数据成员;
3) 没有定义任何构造函数。如果有,也不含参数,并且为protected;
4) 如果是子类,也只能继承满足上述条件并以Interface为后缀的类。
9. 操作符重载
一般不要重载操作符,尤其是赋值操作(operator=)比较阴险,应避免重载。如果需要的话,可以定义类似Equals()、CopyFrom()等函数。
10.存取控制
将数据成员私有化,并提供相关存取函数,如定义变量foo_及取值函数 foo()、赋值函数set_foo()。
存取函数的定义一般内联在头文件中。

11.声明次序
定义次序如下:
public:
protected:
private:

如果那一块没有,直接忽略即可。
每一块中,声明次序一般如下:
1) typedefs 和 enums;
2) 常量;
3) 构造函数;
4) 析构函数;
5) 成员函数,含静态成员函数;
6) 数据成员,含静态数据成员。
宏DISALLOW_COPY_AND_ASSIGN置于private:块之后,作为类的最后部分。
12.编写短小函数
函数尽量短小、简单,便于他人阅读和修改代码。
如果函数超过40行,可以考虑在不影响程序结构的情况下将其分割一下。

四、智能指针和其他C++特性
需要使用智能指针的话,scoped_ptr完全可以胜任。在非常特殊的情况下,应该只使用std::tr1::shared_ptr,任何情况下都不要使用auto_ptr。
1.引用参数
输入参数为值或常数引用,输出参数为指针;输入参数可以是常数指针,但不能使用非常数引用形参。
void Foo(const string &in, string *out);
2.函数重载
仅在输入参数类型不同、功能相同时使用重载函数(含构造函数),不要使用函数重载模仿缺省函数参数。
3.缺省参数
禁止使用缺省函数参数。
缺省参数为很少涉及的例外情况提供了少定义一些函数的方便。
缺省参数使得复制粘贴以前的代码难以呈现所有参数,当缺省参数不适用于新代码时可能导致重大问题。
4.变长数组和alloca
禁止使用变长数组和alloca()。
它们在堆栈(stack)上根据数据分配大小可能导致难以发现的内存泄漏。
5.友元
允许合理使用友元类及友元函数。
友元延伸了(但没有打破)类的封装界线,当你希望只允许另一个类访问某个成员时,使用友元通常比将
其声明为public 要好得多。
6.异常
不要使用 C++异常。
函数有可能在不确定的地方返回,从而导致代码管理和调试困难。
7.运行时类型识别(Run-Time Type Information, RTTI)
除单元测试外,不要使用RTTI。
8.类型转换(Casting)
使用static_cast<>()等C++的类型转换,不要使用int y = (int)x或int y = int(x);。
使用C++风格而不要使用C风格类型转换:
1) static_cast:和C风格转换相似可做值的强制转换,或指针的父类到子类的明确的向上转换;
2) const_cast:移除const属性;
3) reinterpret_cast:指针类型和整型或其他指针间不安全的相互转换,仅在你对所做一切了然于心时使用;
4) dynamic_cast:除测试外不要使用,除单元测试外,如果你需要在运行时确定类型信息,说明设计有缺
陷(参考 RTTI)。
9.流(Streams)
只在记录日志时使用流,流是printf()和scanf()的替代。
10.前置自增减(++i/--i)
迭代器和其他模板对象使用前缀形式(++i)的自增、自减。
不考虑返回值的话,前置自增(++i)通常要比后置自增(i++)效率更高,因为后置的自增自减需要对表达式的值i进行一次拷贝,如果i是迭代器或其他非数值类型,拷贝的代价是比较大的。
11.const的使用
强烈建议你在任何可以使用的情况下都要使用const。
如果你向一个函数传入const变量,函数原型中也必须是const的(否则变量需要const_cast类型转换)
如果函数不会修改传入的引用或指针类型的参数,这样的参数应该为const;
const int* foo
12.整型
<stdint.h>定义了int16_t、uint32_t、int64_t等整型,在需要确定大小的整型时可以使用它们代替short、unsigned long long等。
不要使用uint32_t等无符号整型,除非你是在表示一个位组(bit pattern)而不是一个数值。
13.64位下的可移植性
代码在64位和32位的系统中,原则上应该都比较友好。
14.预处理宏
使用宏时要谨慎,尽量以内联函数、枚举和常量代替之。
15.0和NULL
整数用0,实数用0.0,指针用NULL,字符(串)用‘\0‘。
16.sizeof
尽可能用sizeof(varname)代替sizeof(type)。
17.Boost库
只使用Boost中被认可的库。

五、命名约定

技术分享

 
六、代码注释
1.注释风格
使用//或/* */,统一就好。
2.文件注释
在每一个文件开头加入版权公告,然后是文件内容描述
3.类注释
每个类的定义要附着描述类的功能和用法的注释。
4.函数注释
函数声明处注释的内容:
1) inputs(输入)及outputs(输出);
2) 对类成员函数而言:函数调用期间对象是否需要保持引用参数,是否会释放这些参数;
3) 如果函数分配了空间,需要由调用者释放;
4) 参数是否可以为 NULL;
5) 是否存在函数使用的性能隐忧;
6) 如果函数是可重入的,其同步前提是什么?
函数定义:
每个函数定义时要以注释说明函数功能和实现要点,如使用的漂亮代码、实现的简要步骤、如此实现的理由、为什么前半部分要加锁而后半部分不需要。
5.变量注释
通常变量名本身足以很好说明变量用途,特定情况下,需要额外注释说明。
6.实现注释
对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。
7.标点、拼写和语法
留意标点、拼写和语法,写的好的注释比差的要易读的多。
8.TODO注释
对那些临时的、短期的解决方案,或已经够好但并不完美的代码使用TODO注释。
// TODO(kl@gmail.com): Use a "*" here for concatenation operator.

七、格式
1.行长度
每一行代码字符数不超过80。
2.非ASCII字符
尽量不使用非ASCII字符,使用时必须使用UTF-8格式。
3.空格还是制表位
只使用空格,每次缩进2个空格。
4.函数声明与定义
返回类型和函数名在同一行,合适的话,参数也放在同一行。
5.函数调用
尽量放在同一行,否则,将实参封装在圆括号中。
 6.条件语句
更提倡不在圆括号中添加空格,关键字else另起一行。
7.循环和开关选择语句
switch语句可以使用大括号分块;空循环体应使用{}或continue。
8.指针和引用表达式
句点(.)或箭头(->)前后不要有空格,指针/地址操作符(*、&)后不要有空格。
x = *p;
p = &x;
x = r.y;
x = r->y;
在声明指针变量或参数时,星号与类型或变量名紧挨都可以,个人比较习惯与变量紧挨的方式。
char *c;
const string &str;

char* c;
const string& str;
9.布尔表达式
如果一个布尔表达式超过标准行宽(80字符),如果断行要统一一下。
10.函数返回值
return 表达式中不要使用圆括号。
11.变量及数组初始化
选择=还是()。
12.预处理指令
预处理指令不要缩进,从行首开始。
即使预处理指令位于缩进代码块中,指令也应从行首开始。
13.类格式
关键词 public:、 protected:、 private:要缩进1个空格,且这三个关键词没有缩进。
14.初始化列表
构造函数初始化列表放在同一行或按四格缩进并排几行。
15.命名空间格式化
命名空间内容不缩进。
命名空间不添加额外缩进层次。
16.水平空白
不要在行尾添加无谓的空白
17.垂直空白
垂直空白越少越好
函数头、尾不要有空行。
代码块头、尾不要有空行。

学习笔记:google c++ 编程风格指南

标签:封装   pre   增强   streams   延伸   span   函数返回值   rtu   友元   

原文地址:http://www.cnblogs.com/hiram-zhang/p/7691260.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!