C++代码规范

                                                            目录

一、       头文件    1

1.     define的保护... 1

2.     头文件依赖... 1

3.     内联函数... 1

4.     -inl.h文件... 1

5.     函数参数顺序... 1

6.     包含文件的名称及次序... 2

二、       作用域    3

1.     非成员函数、静态成员函数和全局函数... 3

2.     局部变量... 3

3.     全局变量... 3

三、           3

1.     构造函数(Constructor)的职责... 4

2.     默认构造函数(Default Constructors... 4

3.     明确的构造函数(Explicit Constructors... 4

4.     拷贝构造函数(Copy Constructors... 5

5.     结构体和类(Structs vs. Classes... 5

6.     继承(Inheritance... 5

7.     接口(Interface... 5

8.     操作符重载(Operator Overloading... 6

9.     存取控制(Access Control... 6

10.        声明次序(Declaration Order... 6

11.        编写短小函数(Write Short Functions... 7

四、       其他C++特性    7

1.     引用参数(Reference Arguments... 7

2.     函数重载(Function Overloading... 7

3.     缺省参数(Default Arguments... 7

4.     友元(Friends... 7

5.     异常(Exceptions... 7

6.     类型转换(Casting... 7

7.     前置自增和自减(Preincrementand Predecrement... 7

8.     const的使用(Use of const... 8

9.     整型(Integer Types... 8

10.        预处理宏(Preprocessor Macros... 8

11.        0NULL0 and NULL... 9

12.        sizeofsizeof... 9

13.        Boost库(Boost... 9

五、       命名约定    9

1.     通用命名规则(General Naming Rules... 9

2.     文件命名(File Names... 10

3.     类型命名(Type Names... 11

4.     变量命名(Variable Names... 11

5.     常量命名(Constant Names... 12

6.     函数命名(Function Names... 12

7.     命名空间(Namespace Names... 12

8.     枚举命名(Enumerator Names... 13

9.     宏命名(Macro Names... 13

六、       注释                                                      13

1.     注释风格(Comment Style... 13

2.     TODO注释(TODO Comments... 15

七、       格式                                                      15

1.     行长度(Line Length... 15

2.     ASCII字符(Non-ASCII Characters... 15

3.     空格缩进... 15

4.     函数声明与定义(Function Declarations andDefinitions... 15

5.     函数调用(Function Calls... 17

6.     条件语句(Conditionals... 18

7.     循环和开关选择语句(Loops and Switch Statements... 19

8.     指针和引用表达式(Pointers and ReferenceExpressions... 19

9.     布尔表达式(BooleanExpressions... 20

10.        函数返回值(Return Values... 21

11.        变量及数组初始化(Variable and ArrayInitialization... 21

12.        预处理指令(Preprocessor Directives... 21

13.        类格式(Class Format... 21

14.        初始化列表(Initializer Lists... 22

15.        命名空间格式化(Namespace Formatting... 23

16.        水平留白(Horizontal Whitespace... 23

17.        垂直留白(Vertical Whitespace... 25

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

一、       头文件

通常,每一个.cpp文件(C++的源文件)都有一个对应的.h文件(头文件),也有一些例外,如单元测试代码和只包含main().cpp文件。

1.       define的保护

所有头文件都应该使用#define防止头文件被多重包含(multiple inclusion),命名格式当是:<PROJECT>_<PATH>_<FILE>_H_

为保证唯一性,头文件的命名应基于其所在项目源代码树的全路径。例如,项目foo中的头文件foo/src/bar/baz.h按如下方式保护:

#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_

2.       头文件依赖

使用前置声明(forwarddeclarations)尽量减少.h文件中#include的数量。

3.       内联函数

只有当函数只有10行甚至更少时才会将其定义为内联函数(inline function)。

4.       -inl.h文件

复杂的内联函数的定义,应放在后缀名为-inl.h的头文件中。

5.       函数参数顺序

定义函数时,参数顺序为:输入参数在前,输出参数在后。

int function( const int&inut, int * output);

这一点并不是必须遵循的规则,输入/输出两用参数(通常是类/结构体变量)混在其中,会使得规则难以遵循。

6.       包含文件的名称及次序

将包含次序标准化可增强可读性、避免隐藏依赖(hidden dependencies,译者注:隐藏依赖主要是指包含的文件中编译时),次序如下:cpp文件对应的.h文件、C库、C++库、其他库的.h、项目内的.h

项目内头文件应按照项目源代码目录树结构排列,并且避免使用UNIX文件路径.(当前目录)和..(父目录)。例如,google-awesome-project/src/base/logging.h应像这样被包含:

#include"base/logging.h"

相同目录下头文件按字母序。

举例来说,google-awesome-project/src/foo/internal/fooserver.cpp的包含次序如下:

#include"foo/public/fooserver.h"  // 优先位置

#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include"base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/public/bar.h"

 

 

 

 

 

 

 

 

 

二、       作用域

1.       非成员函数、静态成员函数和全局函数

使用命名空间中的非成员函数或静态成员函数,尽量不要使用全局函数。

2.       局部变量

函数变量使用统一入口和出口。

int function() {

    char *a= NULL;

const size_t size =10;

 a = new char[size];

if (NULL == a) {

gotoclearup:

}

cleanup:

      if (a != NULL) {

           delete []a;

       }

}

3.       全局变量

class类型的全局变量是被禁止的,内建类型的全局变量是允许的,当然多线程代码中非常数全局变量也是被禁止的。永远不要使用函数返回值初始化全局变量。静态成员变量视作全局变量,所以,也不能是class类型!

三、      

1.       构造函数(Constructor)的职责

构造函数中只进行那些没有实际意义的初始化,使用Init()方法集中初始化为有意义的数据。

2.       默认构造函数(Default Constructors

如果一个类定义了若干成员变量又没有其他构造函数,需要定义一个默认构造函数,否则编译器将自动生产默认构造函数。

3.       明确的构造函数(Explicit Constructors

对单参数构造函数使用C++关键字explicitexplicit 可以有效得防止构造函数的隐式转换带来的错误或者误解

class String {

      String ( int n ); //本意是预先分配n个字节给字符串

String ( const char* p ); // C风格的字符串p作为初始化值

//…

}

下面两种写法比较正常:

String s2 ( 10);   //OK 分配10个字节的空字符串

String s3 =String ( 10 ); //OK 分配10个字节的空字符串

 

下面两种写法就比较疑惑了:

String s4 =10; //编译通过,也是分配10个字节的空字符串

String s5 =‘a’; //编译通过,分配int‘a’)个字节的空字符串

 

s4 s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。

为了避免这种错误的发生,我们可以声明显示的转换,使用explicit 关键字:

class String {

      explicit String ( int n ); //本意是预先分配n个字节给字符串

String ( constchar* p ); // C风格的字符串p作为初始化值

//…

}

加上explicit就抑制了String( int n )的隐式转换,

 

下面两种写法仍然正确:

String s2 ( 10);   //OK 分配10个字节的空字符串

String s3 =String ( 10 ); //OK 分配10个字节的空字符串

 

下面两种写法就不允许了:

String s4 =10; //编译不通过,不允许隐式的转换

String s5 =‘a’; //编译不通过,不允许隐式的转换

4.       拷贝构造函数(Copy Constructors

仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数;不需要拷贝时应使用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)情况。

在将类作为STL容器值得时候,你可能有使类可拷贝的冲动。类似情况下,真正该做的是使用指针指向STL容器中的对象,可以考虑使用std::tr1::shared_ptr

5.       结构体和类(Structs vs. Classes

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

6.       继承(Inheritance

使用组合通常比使用继承更适宜,如果使用继承的话,只使用公共继承。

7.       接口(Interface

接口是指满足特定条件的类,这些类以Interface为后缀。

定义:当一个类满足以下要求时,称之为纯接口:

1) 只有纯虚函数("=0")和静态函数(下文提到的析构函数除外);

2) 没有非静态数据成员;

3) 没有定义任何构造函数。如

果有,也不含参数,并且为protected

4) 如果是子类,也只能继承满足上述条件并以Interface为后缀的类。

结论:。只有在满足上述需要时,类才以Interface结尾,但反过来,满足上述需要的类未必一定以Interface结尾。

8.       操作符重载(Operator Overloading

除少数特定环境外,不要重载操作符。

有些STL算法确实需要重载operator==时可以这么做,不要忘了提供文档说明原因。

9.       存取控制(Access Control

将数据成员私有化,并提供相关存取函数,如定义变量foo_及取值函数foo()、赋值函数set_foo()。存取函数的定义一般内联在头文件中。

10.  声明次序(Declaration Order

在类中使用特定的声明次序:public:private:之前,成员函数在数据成员(变量)前。

定义次序如下:public:protected:private:,如果那一块没有,直接忽略即可。

每一块中,声明次序一般如下:

1) typedefsenums

2) 常量;

3) 构造函数;

4) 析构函数;

5) 成员函数,含静态成员函数;

6) 数据成员,含静态数据成员。

DISALLOW_COPY_AND_ASSIGN置于private:块之后,作为类的最后部分。参考拷贝构造函数

.cpp文件中函数的定义应尽可能和声明次序一致。

11.  编写短小函数(Write Short Functions

倾向于选择短小、凝练的函数,以不超过40行为宜。

四、       其他C++特性

1.       引用参数(Reference Arguments

所有按引用传递的参数必须加上const,map除外。

2.       函数重载(Function Overloading

仅在输入参数类型不同、功能相同时使用重载函数(含构造函数),不要使用函数重载模仿缺省函数参数。

3.       缺省参数(Default Arguments

可以使用缺省函数参数。

4.       友元(Friends

允许合理使用友元类及友元函数。

5.       异常(Exceptions

不要使用C++异常。

6.       类型转换(Casting

使用static_cast<>()C++的类型转换,不要使用int y = (int)xinty = int(x);

7.       前置自增和自减(Preincrement andPredecrement

结论:对简单数值(非对象)来说,两种都无所谓,对迭代器和模板类型来说,要使用前置自增(自减)。

8.       const的使用(Use of const

在任何可以使用的情况下都要使用const,map除外

9.       整型(Integer Types

C++内建整型中,唯一用到的是int,如果程序中需要不同大小的变量,可以使用<stdint.h>中的精确宽度(precise-width)的整型,如int16_t

10.  预处理宏(Preprocessor Macros

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

下面给出的用法模式可以避免一些使用宏的问题,供使用宏时参考:

1) 不要在.h文件中定义宏;

2) 使用前正确#define,使用后正确#undef

3) 不要只是对已经存在的宏使用#undef,选择一个不会冲突的名称;

4) 不使用会导致不稳定的C++构造的宏,至少文档说明其行为。

如下所示,类Test可能会构造失败。

Class Test {

public

       Test() {

              _p = new char[10];

       }

private:

       char *_p;

};

#define  NEW_TEST new Test()

Test * p = NEW_TEST;

11.  0NULL0 and NULL

整数用0,实数用0.0,指针用NULL,字符(串)用'\0'

12.  sizeofsizeof

尽可能用sizeof(varname)代替sizeof(type)。使用sizeof(varname)是因为当变量类型改变时代码自动同步,有些情况下sizeof(type)或许有意义,还是要尽量避免,如果变量类型改变的话不能同步。

Struct data;

memset(&data, 0, sizeof(data));

memset(&data, 0, sizeof(Struct));

13.  Boost库(Boost

只使用Boost中被认可的库,推荐只是用智能指针相关的库。

五、       命名约定

1.       通用命名规则(General Naming Rules

函数命名、变量命名、文件命名应具有描述性,不要过度缩写,类型和变量应该是名词,函数名可以用命令性动词。

如何命名

尽可能给出描述性名称,不要节约空间:

int num_errors;                  // Good.

int num_completed_connections;   // Good.

丑陋的命名使用模糊的缩写或随意的字符:

int n;                           // Bad -meaningless.

int nerr;                        // Bad - ambiguousabbreviation.

int n_comp_conns;                // Bad - ambiguousabbreviation.

类型和变量名一般为名词:如FileOpenernum_errors。函数名通常是指令性的,如OpenFile()set_num_errors(),访问函数需要描述的更细致,要与其访问的变量相吻合。

缩写

除非放到项目外也非常明了,否则不要使用缩写,例如:

// Good

// These show proper names with no abbreviations.

int num_dns_connections;  // Most people know what "DNS"stands for.

int price_count_reader;   // OK, price count. Makes sense.

 

// Bad!

// Abbreviations can be confusing or ambiguousoutside a small group.

int wgc_connections; // Only your group knows what this stands for.

int pc_reader;       // Lots of things can be abbreviated "pc".

2.       文件命名(File Names

文件名要全部小写,用下划线(_)相连。

my_useful_class.cpp

C++文件以.cpp结尾,头文件以.h结尾。

不要使用已经存在于/usr/include下的文件名(译者注,对UNIXLinux等系统而言),如db.h

通常,尽量让文件名更加明确,http_server_logs.h就比logs.h要好,定义类时文件名一般成对出现,如foo_bar.hfoo_bar.cpp,对应类FooBar

内联函数必须放在.h文件中,如果内联函数比较短,就直接放在.h中。如果代码比较长,可以放到以-inl.h结尾的文件中。对于包含大量内联代码的类,可以有三个文件:

url_table.h     // The class declaration.

url_table.cpp    // The class definition.

url_table-inl.h // Inline functions that include lots of code.

3.       类型命名(Type Names

类型命名每个单词以大写字母开头,不包含下划线:MyExcitingClassMyExcitingEnum

所有类型命名——类、结构体、类型定义(typedef)、枚举——使用相同约定,例如:

// classes and structs

class UrlTable { ...

class UrlTableTester { ...

struct UrlTableProperties { ...

 

// typedefs

typedef hash_map<UrlTableProperties *, string>PropertiesMap;

 

// enums

enum UrlTableErrors { ...

4.       变量命名(Variable Names

变量名一律小写,单词间以下划线相连,类的成员变量以下划线开头,如my_exciting_local_variable_my_exciting_member_variable。不用m_开头,也不用_结尾。

普通变量命名

string table_name; // OK - uses underscore.

stringtableName;   // Bad - mixed case.

类数据成员

结构体的数据成员可以和普通变量一样,不用像类那样接下划线:

struct UrlTableProperties {

  string name;

  intnum_entries;

}

全局变量

对全局变量没有特别要求,少用就好,可以以g_或其他易与局部变量区分的标志为前缀。

5.       常量命名(Constant Names

在名称前加kkDaysInAWeek。所有编译时常量(无论是局部的、全局的还是类中的)和其他变量保持些许区别,k后接大写字母开头的单词:

const int kDaysInAWeek = 7;

6.       函数命名(Function Names

函数大小写混合,存取函数则要求与变量名匹配:myExcitingFunction()myExcitingMethod()

普通函数

函数名以小写字母开头,每个单词首字母大写,没有下划线:

addTableEntry()

deleteUrl()

存取函数

存取函数要与存取的变量名匹配,这儿摘录一个拥有实例变量num_entries_的类:

class MyClass {

public:

  ...

    int numEntries() const { return _num_entries;}

    void SetNumEntries(int num_entries) { _num_entries= num_entries; }

 

private:

  int _num_entries;

};

其他短小的内联函数名也可以使用小写字母,例如,在循环中调用这样的函数甚至都不需要缓存其值,小写命名就可以接受。

7.       命名空间(Namespace Names

命名空间的名称是全小写的,其命名基于项目名称和目录结构:google_awesome_project

8.       枚举命名(Enumerator Names

枚举值应全部大写,单词间以下划线相连:MY_EXCITING_ENUM_VALUE

枚举名称属于类型,因此大小写混合:UrlTableErrors

enum UrlTableErrors {

  OK = 0,

 ERROR_OUT_OF_MEMORY,

 ERROR_MALFORMED_INPUT,

};

9.       宏命名(Macro Names

通常是不使用宏的,如果绝对要用,其命名像枚举命名一样全部大写、使用下划线:

#define ROUND(x) ...

#define PI_ROUNDED 3.0

MY_EXCITING_ENUM_VALUE

六、       注释

1.       注释风格(Comment Style

使用//或/* */,统一就好。

//或/* */都可以,//只是用的更加广泛,在如何注释和注释风格上确保统一

行注释

比较隐晦的地方要在行尾加入注释,可以在代码之后空两格加行尾注释,如:

// If we have enough memory,mmap the data portion too.

mmap_budget =max<int64>(0, mmap_budget - index_->length());

if (mmap_budget >=data_size_ && !MmapData(mmap_chunk_bytes, mlock))

  return; // Error already logged.

注意,有两块注释描述这段代码,当函数返回时注释提及错误已经被记入日志。

前后相邻几行都有注释,可以适当调整使之可读性更好:

...

DoSomething();                  // Comment here so thecomments line up.

DoSomethingElseThatIsLonger();  // Comment here so there are two spacesbetween

                                // the code andthe comment.

...

NULLtrue/false123……

向函数传入、布尔值或整数时,要注释说明含义,或使用常量让代码望文知意,比较一下:

bool success =CalculateSomething(interesting_value,

                                  10,

                                  false,

                                  NULL);  // What are these arguments??

和:

bool success =CalculateSomething(interesting_value,

                                  10,    // Default base value.

                                  false,  // Not the first time we're calling this.

                                  NULL);  // No callback.

使用常量或描述性变量:

const int kDefaultBaseValue =10;

const bool kFirstTimeCalling =false;

Callback *null_callback =NULL;

bool success =CalculateSomething(interesting_value,

                                 kDefaultBaseValue,

                                 kFirstTimeCalling,

                                 null_callback);

2.       TODO注释(TODO Comments

对那些临时的、短期的解决方案,或已经够好但并不完美的代码使用TODO注释。

这样的注释要使用全大写的字符串TODO,后面括号(parentheses)里加上你的大名、邮件地址等,还可以加上冒号(colon):目的是可以根据统一的TODO格式进行查找:

// TODO([email protected]): Use a"*" here for concatenation operator.

// TODO(Zeke) change this touse relations.

如果加上是为了在将来某一天做某事,可以加上一个特定的时间("Fix by November2005")或事件("Removethis code when all clients can handle XML responses.")。

七、       格式

1.       行长度(Line Length

每一行代码字符数不超过80

2.       ASCII字符(Non-ASCII Characters

尽量不使用非ASCII字符,使用时必须使用UTF-8格式。

3.       空格缩进

只使用空格,每次缩进4个空格。

4.       函数声明与定义(Function Declarations andDefinitions

返回类型和函数名在同一行,合适的话,参数也放在同一行。

ReturnType ClassName::FunctionName(Type par_name1,Type par_name2) {

 DoSomething();

  ...

}

如果同一行文本较多,容不下所有参数:

ReturnType ClassName::ReallyLongFunctionName(Typepar_name1,

                                            Type par_name2,

                                            Type par_name3) {

 DoSomething();

  ...

}

甚至连第一个参数都放不下:

ReturnTypeLongClassName::ReallyReallyReallyLongFunctionName(

    Typepar_name1,  // 4 space indent

    Typepar_name2,

    Typepar_name3) {

 DoSomething();  // 2 space indent

  ...

}

注意以下几点:

1) 返回值总是和函数名在同一行;

2) 左圆括号(openparenthesis)总是和函数名在同一行;

3) 函数名和左圆括号间没有空格;

4) 圆括号与参数间没有空格;

5) 左大括号(open curlybrace)总在最后一个参数同一行的末尾处;

6) 右大括号(closecurly brace)总是单独位于函数最后一行;

7) 右圆括号(closeparenthesis)和左大括号间总是有一个空格;

8) 函数声明和实现处的所有形参名称必须保持一致;

9) 所有形参应尽可能对齐;

如果函数为const的,关键字const应与最后一个参数位于同一行。

// Everything in this function signature fits on asingle line

ReturnType FunctionName(Type par) const {

  ...

}

 

// This function signature requires multiple lines,but

// the const keyword is on the line with the lastparameter.

ReturnType ReallyLongFunctionName(Type par1,

                                  Type par2)const {

  ...

}

如果有些参数没有用到,在函数定义处将参数名注释起来:

// Always have named parameters in interfaces.

class Shape {

public:

    virtual void Rotate(double radians) = 0;

}

 

// Always have named parameters in the declaration.

class Circle : public Shape {

public:

    virtual void Rotate(double radians);

}

 

// Comment out unused named parameters indefinitions.

void Circle::Rotate(double /*radians*/) {}

// Bad - if someone wants to implement later, it'snot clear what the

// variable means.

void Circle::Rotate(double) {}

5.       函数调用(Function Calls

尽量放在同一行,否则,将实参封装在圆括号中。

bool retval = DoSomething(argument1, argument2,argument3);

如果同一行放不下,可断为多行,后面每一行都和第一个实参对齐,左圆括号后和右圆括号前不要留空格:

bool retval =DoSomething(averyveryveryverylongargument1,

                          argument2,argument3);

如果函数参数比较多,可以出于可读性的考虑每行只放一个参数:

bool retval = DoSomething(argument1,

                          argument2,

                          argument3,

                          argument4);

 

如果函数名太长,以至于超过行最大长度,可以将所有参数独立成行:

if (...) {

  ...

  ...

  if (...) {

   DoSomethingThatRequiresALongFunctionName(

       very_long_argument1,  // 4 spaceindent

       argument2,

       argument3,

       argument4);

  }

6.       条件语句(Conditionals

不在圆括号中添加空格,关键字else另起一行,所有分支用大括号包含起来。

if (condition) { // no spaces inside parentheses

  ...  // 2 space indent.

} else {  //The else goes on the same line as the closing brace.

  ...

}

注意所有情况下if和左圆括号间有个空格,右圆括号和左大括号间也要有个空格:

if(condition)    // Bad - space missing after IF.

if (condition){  // Bad - space missing before {.

if(condition){   // Doubly bad.

if (condition) { // Good - proper space after IF and before {.

7.       循环和开关选择语句(Loops and SwitchStatements

switch语句可以使用大括号分块;空循环体应使用{}continuecase块可以使用大括号也可以不用。

switch (var) {

  case 0:{  // 2 space indent

    ...      // 4 space indent

    break;

  }

  case 1: {

    ...

    break;

  }

  default: {

   assert(false);

  }

}

空循环体应使用{}continue,而不是一个简单的分号:

while (condition) {

  // Repeattest until it returns false.

}

for (int i = 0; i < kSomeNumber; ++i) {}  // Good - empty body.

while (condition) continue;  // Good - continue indicates no logic.

while (condition); // Bad - looks like part of do/while loop.

8.       指针和引用表达式(Pointers and ReferenceExpressions

句点(.)或箭头(->)前后不要有空格,指针/地址操作符(*、&)后不要有空格。

下面是指针和引用表达式的正确范例:

x = *p;

p = &x;

x = r.y;

x = r->y;

注意:

1) 在访问成员时,句点或箭头前后没有空格;

2) 指针操作符*&后没有空格。

在声明指针变量或参数时,星号与变量名紧挨:

// These are fine, space preceding.

char *c;

const string &str;

 

// These are fine, space following.

char* c;    //but remember to do "char* c, *d, *e, ...;"!

const string& str;

char * c;  //Bad - spaces on both sides of *

const string & str;  // Bad - spaces on both sides of &

9.       布尔表达式(Boolean Expressions

如果一个布尔表达式超过标准行宽,需要断行,逻辑操作符总位于行尾:

if (this_one_thing > this_other_thing &&

   a_third_thing == a_fourth_thing &&

   yet_another & last_one) {

  ...

}

两个逻辑与(&&)操作符都位于行尾,可以考虑额外插入圆括号,合理使用的话对增强可读性是很有帮助的。

10.  函数返回值(Return Values

return表达式中不要使用圆括号。

return x;  //not return(x);

11.  变量及数组初始化(Variable and ArrayInitialization

选择=

int x = 3;

string name = "Some Name";

12.  预处理指令(Preprocessor Directives

预处理指令不要缩进,即使它位于缩进代码块中,指令也应从行首开始。

// Good - directives at beginning of line

  if(lopsided_score) {

#if DISASTER_PENDING      // Correct -- Starts at beginning of line

   DropEverything();

#endif

   BackToNormal();

  }

// Bad - indented directives

  if(lopsided_score) {

    #if DISASTER_PENDING  // Wrong! The "#if" should be at beginning of line

   DropEverything();

   #endif                //Wrong!  Do not indent "#endif"

   BackToNormal();

  }

13.  类格式(Class Format

声明属性依次序是public:protected:private:,不缩进。

类声明(对类注释不了解的话,参考第六篇中的类注释一节)的基本格式如下:

class MyClass : public OtherClass {

public::     // Note the 1 space indent!

    MyClass(); // Regular 2 space indent.

    explicit MyClass(int var);

    ~MyClass() {}

 

    void SomeFunction();

    void SomeFunctionThatDoesNothing() {

  }

 

    void setSomeVar(int var) { _some_var = var; }

    int someVar() const { return _some_var; }

 

private::

    bool SomeInternalFunction();

 

    int _some_var;

    int _some_other_var;

    DISALLOW_COPY_AND_ASSIGN(MyClass);

};

注意:

1) 所以基类名应在80列限制下尽量与子类名放在同一行;

2) 关键词public:、protected:private:不缩进

3) 除第一个关键词外,其他关键词前空一行,如果类比较小的话也可以不空;

4) 这些关键词后不要空行;

5) public放在最前面,然后是protectedprivate

14.  初始化列表(Initializer Lists

构造函数初始化列表放在同一行或按四格缩进并排几行。

两种可以接受的初始化列表格式:

// When it all fits on one line:

MyClass::MyClass(int var) : some_var_(var),some_other_var_(var + 1) {

// When it requires multiple lines, indent 4 spaces,putting the colon on

// the first initializer line:

MyClass::MyClass(int var)

    :some_var_(var),             // 4 spaceindent

     some_other_var_(var + 1) {  //lined up

  ...

 DoSomething();

  ...

}

15.  命名空间格式化(Namespace Formatting

命名空间内容不缩进。

namespace {

 

void foo() { // Correct.  No extra indentationwithin namespace.

  ...

}

 

// namespace

16.  水平留白(Horizontal Whitespace

水平留白的使用因地制宜。不要在行尾添加无谓的留白。

普通

void f(bool b) { // Open braces should always have a space before them.

  ...

int i = 0;  //Semicolons usually have no space before them.

int x[] = { 0 }; // Spaces inside braces for array initialization are

int x[] = {0};   // optional.  If you use them, putthem on both sides!

// Spaces around the colon in inheritance andinitializer lists.

class Foo : public Bar {

 public:

  // Forinline function implementations, put spaces between the braces

  // and theimplementation itself.

  Foo(int b) :Bar(), baz_(b) {}  // No spaces insideempty braces.

  void Reset(){ baz_ = 0; }  // Spaces separatingbraces from implementation.

  ...

循环和条件语句

if (b) {         // Space after the keyword in conditions and loops.

} else {         // Spaces around else.

}

while (test) {}  // There is usually no space inside parentheses.

switch (i) {

for (int i = 0; i < 5; ++i) {

switch ( i ) {   // Loops and conditions may have spaces inside

if ( test ) {    // parentheses, but this is rare. Be consistent.

for ( int i = 0; i < 5; ++i ) {

for ( ; i < 5 ; ++i) {  // For loops always have a space after the

  ...                   // semicolon, and may have aspace before the

                        // semicolon.

switch (i) {

  case 1:         // No space before colon in a switchcase.

    ...

  case 2:break;  // Use a space after a colon ifthere's code after it.

操作符

x = 0;             // Assignment operators always have spaces around them.

x = -5;            // No spaces separating unary operators and their

++x;               // arguments.

if (x && !y)

  ...

v = w * x + y / z; // Binary operators usually have spaces around them,

v = w*x + y/z;     // but it's okay to remove spaces around factors.

v = w * (x + z);   // Parentheses should have no spaces inside them.

 

模板和转换

vector<string> x;           // No spaces inside the angle

y = static_cast<char*>(x);  // brackets (< and >), before

                            // <, or between>( in a cast.

vector<char *> x;           // Spaces between type and pointerare

                            // okay, but beconsistent.

set<list<string> > x;       // C++ requires a space in > >.

set< list<string> > x;      // You may optionally make use

                            // symmetric spacing in < <.

17.  垂直留白(Vertical Whitespace

垂直留白越少越好,不要在两个函数定义之间空超过2行,函数体头、尾不要有空行,函数体中也不要随意添加空行。

函数头、尾不要有空行:

void Function() {

 

  //Unnecessary blank lines before and after

 

}

代码块头、尾不要有空行:

while (condition) {

  //Unnecessary blank line after

 

}

if (condition) {

 

  //Unnecessary blank line before

}

if-else块之间空一行还可以接受:

if (condition) {

  // Somelines of code too small to move to another function,

  // followedby a blank line.

 

} else {

  // Anotherblock of code

}

发布了75 篇原创文章 · 获赞 17 · 访问量 17万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章