美文网首页
C++编程规范

C++编程规范

作者: 谭英智 | 来源:发表于2022-04-09 19:03 被阅读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 文件

    作用域

    命名空间

    • 鼓励在cpp文件中使用具名命名空间

    • 不应该使用using引入整个命名空间

      //禁止把整个命名空间引入 -- 会污染命名空间
      using namespace foo;
      
    • 不应该在头文件使用命名空间别名

      //禁止使用别名命名空间在头文件中 -- 会导致别名命名空间成为公开API的一部分
      namespace baz = ::foo::bar::baz;
      
    • 禁止使用内联命名空间

      //禁止使用内联 -- 会带来API迷惑
      inline namespace FOO {
      
      }
      

    局部变量

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

    构造函数

    • 不要在构造函数中调用虚函数
    • 不要在构造函数中进行可能失败的初始化

    默认构造函数

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

    显式构造函数

    对于单个参数的构造函数,使用关键字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/

    相关文章

      网友评论

          本文标题:C++编程规范

          本文链接:https://www.haomeiwen.com/subject/snopsrtx.html