C++ 编码规范总结

推荐文档:Google C++ 编程风格

头文件依赖与前向声明

当我们在头文件中需要类的定义时,只需要声明 class CLASSNAME 就可以了,无需使用#include “CLASSNAME.h”

优势:

  • 减少文件依赖,节约编译时间;
  • 更加明确的类的依赖关系。

函数的参数顺序

参数的声明顺序为,输入参数在前,输出参数在后。

  • 输入参数一般为传值和常数引用;
  • 输出参数或输入/输出参数一般为非常数指针。

优势:

  • 通过位置明确参数的作用;
  • 利于代码的合并(用合并软件)。

示例:

class Foo;

void Command(const int nInputParam1,
              const float nInputParam2,
              const Foo& nInputClass1,
              const Foo* nInputClass2,
              void* pOutputParam1);

头文件包含的顺序

顺序:

  1. 先包含类对应头文件
  2. C 系统头文件
  3. C++ 系统头文件
  4. 其他库头文件
  5. 本项目内头文件

之间通过空行区分。

优势:

  • 增加可读性
  • 利于代码合并

局部变量的初始化

在尽可能小的作用域中声明变量,离第一次使用的位置越近越好。

好处:

  • 使得代码易读,避免一些错误。

对于结构体或数组,声明以后,也应立刻进行初始化操作:

TOOLTIP tooltip = {0};
char buff[1024] = {0};

memset(&tooltip, 0, sizeof(tooltip));
memset(buff, 0, 1024);

局部类的初始化

一个类的局部变量会默认做一次构造和析构,应注意避免多次的初始化与析构。

示例:

1
2
3
4
for(int a = 0; a < 1000; a++){
    Foo f;
    f.doFun();
}

在循环内初始化的 f 会构造和析构 1000 次。应改为:

1
2
3
4
Foo f;
for(int a = 0; a < 1000; a++){
    f.doFun();
}

类的初始化(构造函数)

  • 注意类成员的初始化,养成良好的类成员声明习惯(声明后立刻在构造函数中进行初始化操作);
  • 类的初始化虽然很简单,但很多程序员忘记做了,导致不可预知的问题(因为导致变量的初始值不可预料)。

类的拷贝构造函数

编译器会默认为我们的类提供一个赋值操作符函数和拷贝构造函数,但同时也会带来问题。

注意:

  • 禁用不必要的默认拷贝构造和赋值函数。
  • 函数的参数,尽量使用引用或指针,避免拷贝或赋值构造。

深拷贝与浅拷贝:
默认的浅拷贝,两个对象的指针指向相同一块内存。

深拷贝示例:

// 重载赋值操作符
void operator=(const Foo& srcFoo){
    if(this == &srcFoo)  // 防止自复制
        return;
    if(srcFoo.m_pszName){
        size_t nSize = _tcslen(srcFoo.m_pszName);
        if(nSize > 0){
            m_pszName = new wchar_t[nSize + 1];
            _tcscpy_s(m_pszName, nSize + 1, srcFoo.m_pszName);
        }
    }
}

可以通过禁止不提供的拷贝函数,也就是将这些方法声明为私有函数:

// 禁止使用拷贝构造函数和赋值操作的宏
// 应在类的 private: 中使用
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
    TypeName(const TypeName&); \
    void operator=(const TypeName&)
    
class Foo {
private:
    DISALLOW_COPY_AND_ASSIGN(Foo);
    ...

结构体和类

区别:在 C++ 中,struct 和 class 可以起到同样的作用,唯一的区别是 struct 默认方法和成员是 public 的,class 默认是 private 的。
(struct 也可以和 class 一样使用构造和析构函数对数据进行初始化和释放。)

我们约定仅当只有数据的时候使用struct,其他一般使用class。

操作符重载

操作符重载可以为我们的代码编写提供便利,但是也会使我们的代码变得不够直观。
例如增加一个 Equals 方法比直接对 == 操作符重载要来的直观得多。

因此我们一般不要对操作符进行重载。

将类的成员私有化

面向对象编程的一个原则是隐藏内部的数据。有时候我们为了方便直接将数据声明为 public,应避免这种做法,虽然一时间节约了不少编码时间,但有时也会代码极大的不便。

优势:

  • 代码封装性好;
  • 有利于调试(因为所有对成员变量的调试场景都在 get 和 set 方法中)。

类中的声明顺序

顺序:

  1. public
  2. protected
  3. private

没有的块可以忽略。

块内顺序:

  1. typedef 和 enums
  2. 常量
  3. 构造函数
  4. 析构函数
  5. 成员函数,含静态成员函数
  6. 数据成员,含静态数据成员

优势:

  • 代码封装性好;
  • 有利于调试。

编写短小的函数

如果没有特殊的需求,函数的长度控制在40行左右。如果过长,不影响程序的运行的情况将长函数进行分割。

优势:

  • 提取重复的代码;
  • 便于他人阅读和修改;
  • 便于发现和定位bug。

引用参数与 const

如果传入引用型参数,请务必添加上 const。

优势:

  • 约束调用行为;
  • 自解释了参数的作用。

尽量使用 const

尽量使用 const 定义参数类型。

使用的条件:

  • 函数不会修改的引用或指针类型的参数;
  • 不修改数据的函数,指定为 const;
  • 如果类的成员变量在构造后不会改变,声明为const。

优势:

  • 约束变量的操作行为。

示例:

bool Equal(const Point& p1, const Point* p2) const {
}
// 函数的参数,尽量使用引用或指针,避免拷贝或赋值构造。

其他

  • 没有特殊要求,尽量不进行函数重载,通过函数名称进行区分。过多的重载函数有时也会是调用者无从选择。
  • 禁用缺省参数。避免调用者理解错误。
  • 禁用 RTTI(不使用 dynamic_cast)。运行时类型识别本身就说明设计存在问题。利用类型号或者 virtual 方法都可以做到同样的功能。
  • 前置自增或自减的效率要好于后置,特别是迭代器,区别非常大。
  • 尽可能用 sizeof(varname) 而不是 sizeof(type),防止变量类型在运行时被改变了。

变量命名

  • 不要定义无法自解释的名称;
  • 不要拼写错误或者拼写不完整;
  • 类名称全部以大写开头;
  • 结构体,枚举全部大写开头;
  • 变量命名一律小写开头;
  • 类成员变量以 m_ 开头;
  • 所有的全局变量使用 g_ 开头;
  • 常量使用小写 k 开头。如const int m_kIndex
  • 函数名称以大写开头(我之前都是小写的..),单词之前首字母大写;
  • 类的存取函数,取函数以Get开头,设置函数以Set开头;
  • 枚举类型中的值全部大写表示;
  • 宏名称全部大写,单词之间通过下划线进行分割。

0、NULL 与初始化

  • 整数用0
  • 实数用0.0
  • 指针用NULL
  • 字符串用“\0”

优势:通过初始化的值就可以判断变量的类型。

匈牙利命名规则

类型 + 作用名称
如 bVisible, pVecBooks, nIndexDay

类型字符示例
指针ppWnd pData
函数fnfnCalc
无效vvData
句柄hhBitmap
长整型llDays
布尔bbVisible
浮点型(有时也指文件)ffAngle
双字dwdwStyle
字符串strstrName
短整型nnIndex
双精度浮点ddRotate
计数c(通常用cnt)cIndex
字符ch(通常用c)cByte
整型i(我们通常用n)iIndex
字节bybyData
wwChar
实型rrPi
无符号uuSize

格式要求

  • 一行代码不要过长;
  • 空格作为制表符,两个空格代表一个制表符(VS 设置 - 所有语言 - 制表符,制表符大小和缩进大小都设置为2);
  • 函数声明中返回类型和函数名在同一行中,如果过长对行数的参数进行分行处理,并进行对齐;
  • 函数调用和返回放在同一行中,如果代码过长,对传入的参数进行分行处理;
  • 条件判断的 if 要加括号,左/右大括号要另起一行,else 也是一样;
  • 加减等操作符前后添加空格。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值