C++编程规范

2022-04-09  本文已影响0人  谭英智

背景

C++是很多项目的主要开发语言。项目一般是多人开发,而每个人的编码风格一般各有不同。如果没有一套C++的编程规范,项目内的代码将难以阅读与维护。

因此此文档将对C++的编程风格作一些约定,以便项目内的开发者可以写出风格一致的代码。

下面将围绕以下思维导图展开讨论C++编程规范的细节

c_style_mind

头文件

自包含头文件

头文件应该能够自给自足,例如头文件 foo.h 可以置于 foo.cpp 文件的第一行

换句话说,头文件包含了它所需要的其他头文件,当别的文件引用此头文件的时候,不需要额外引用其他头文件才能够使用。

#define保护

头文件应该使用#define保护,防止头文件被多重包含。

按以下方式保护:

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

内联函数

只有当函数在10行以内才将其定义为内联函数。

内联函数一般不能包含循环、switch语句、递归或者是虚函数。

#include的路径及顺序

例如dir/foo.cpp包含的头文件的次序如下:

  1. dir/foo.h
  2. C 系统文件
  3. C++ 系统文件
  4. 其他库的 .h 文件
  5. 本项目内 .h 文件

作用域

命名空间

局部变量

将函数变量尽量置于最小作用域内,并对变量声明时进行初始化。

构造函数

默认构造函数

如果一个类定义了若干个成员变量又没有其他构造函数,必须定义一个默认构造函数。否则编译器会自动产生一个很糟糕的默认构造函数。

显式构造函数

对于单个参数的构造函数,使用关键字explicit.

拷贝构造函数

仅在一个类需要拷贝一个类的对象时才使用拷贝构造函数。大部分情况下不需要拷贝的类,应该使用DISALLOW_COPY_AND_ASSIGN.

DISALLOW_COPY_AND_ASSIGN的使用方法如下:

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
            TypeName(const TypeName&); \
            void operator=(const TypeName&)

//把拷贝构造和赋值操作声明为private
class Foo {
    public:
        Foo(int f);
        ~Foo();
    
    private:
        DISALLOW_COPY_AND_ASSIGN(Foo);
};

结构体 VS. 类

仅当数据时使用struct。否则使用class

继承

使用组合常常比使用继承更合理。

如果使用继承,一般定义为public继承

多重继承

真正需要多重继承的情况少之又少。

只有一种情况允许使用多重继承:最多只有一个基类时非抽象类,其他基类都是抽象类

运算符重载

只有在少数特定情况下使用。

否则尽量不要使用运算符重载

成员变量

将所有数据成员变量声明为private.。

除非是 static const 类型成员

声明顺序

一般应该以public开始,后跟protected,最有是private

将类似的声明放在一起

函数

参数顺序

输入参数在先,后跟输出参数

编写简短函数

函数一般要求不超过40行

引用输入参数

输入型的引用参数,必须加上const

例如

void foo(const string &in, string& out);

缺省参数

建议使用缺省参数,但不允许在虚函数中使用

语言特性

变长数组和alloca()

不允许使用变长数组和alloca()

异常

不使用异常

运行时类型识别

禁止使用RTTI

RTTI允许程序员通过typeid或者dynamic_cast在运行时识别C++对象的类型

前置自增和自减

对于自增(++i 或 i++),如果自增后,返回值没有被用到,前置自增(++i)要比后置自增(i++)效率更高

const用法

强烈建议在任何可能的情况下使用const

预处理宏

使用宏时需要非常小心,尽量用内联函数、枚举和常量代替

0,nullptr和NULL

整数用0,实数用0.0,指针用nullptr或者NULL,字符用'\0'

sizeof

尽量用sizeof(varname)代替sizeof(type)

模板编程

不要使用复杂的模板编程

命名约定

通用命名规则

好的命名:

int num_errors; // Good.
int num_completed_connections; // Good.
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; // 删减了若干字母.

文件命名

文件名要全部小写,可以包含下划线 (_) 或者连字符 (-)

例如:

my_userful_class.cpp

类命名

类名字的每个单词首字母大写,不包含下划线

例如:MyExcitingClass

变量命名

变量和数据成员名使用小写,单词间使用下划线连接,类成员变量以下划线结尾

例如变量:

string table_name;

例如类数据成员

class Foo {
   ...
   private:
     string table_name_;
};

常量命名

命名以"k"开头,大小写混合,例如:

const int kDaysInAWeek = 7;

函数命名

常规函数使用大小写混合,例如

void OnMessage();

取值和设值函数,使用变量名字来命名,例如:

class Foo {
    public:
        int num_entries() const { return num_entries_;}
    private:
        int num_entries_;
};

命名空间命名

以大小写字母命名

枚举命名

使用常量或宏的命名方法命名

例如:

enum UrlTableErrors {
 kOK = 0,
 kErrorOutOfMemory,
 kErrorMalformedInput,
};
enum AlternateUrlTableErrors {
 OK = 0,
 OUT_OF_MEMORY = 1,
 MALFORMED_INPUT = 2,
};

宏命名

使用大写字母和下划线来命名

注释

类注释

函数注释

函数声明的注释内容:

变量注释

通常根据变量名就可以说明变量用途

实现注释

对于代码中晦涩,重要的地方加以注释

格式

行长度

每行代码不超过80个字符

空格还是制表位

只是用空格,每次缩进2个空格

函数声明和定义

返回类型和函数名在同一行,参数也尽量在同一样,否则参数分行放置

引用自(谷歌C++编程规范)

https://zh-google-styleguide.readthedocs.io/en/latest/

上一篇下一篇

猜你喜欢

热点阅读