C++编程规范(参考Google、华为)
文件名及版权信息
1、文件名
C++文件名全部都是小写,且单词之间用_
分割,如:verilog_parse.cpp
2、版权信息
所有文件均需要统一格式的版权信息。
头文件
1、在.h
中使用#define
来防止头文件被多重包含,并在最后注释出宏的名字
命名格式:<PROJECT>_<FILE>_H_
#ifndef TIMER_FLOW_H_
#define TIMER_FLOW_H_
...
#endif // TIMER_FLOW_H_
2、尽量避免使用前置声明,优先使用#include
来包含相关头文件
包含头文件:
#include "timer.h" // 优先使用
前置声明:
class Timer; // 尽量避免
3、#include
的包含顺序
头文件的包含顺序为:当前.cpp
文件直接关联的头文件、C库文件、C++库文件、其他项目的头文件、本项目中的其他头文件。
// timer.cpp
#include "timer.h" // 关联头文件
#include <stdio.h> // C库文件
#include <string> // C++库文件
#include "verilog.h" // 其他项目的头文件
#include "node.h" // 本项目中的其他头文件
4、头文件应向稳定的方向包含
头文件的包含关系是一种依赖,一般来说,有以下几种包含原则。
应当让不稳定的模块依赖稳定的模块,从而当不稳定的模块发生变化时,不会影响(编译)稳定的模块。
禁止头文件循环依赖,指a.h包含b.h,b.h包含c.h,c.h包含a.h。
禁止包含用不到的头文件。
头文件应当自包含,指任意一个头文件均可独立编译。
作用域
1、在命名空间的最后注释出命名空间的名字
namespace mynamespace
{// 注意不要使用缩进
...
} // namespace mynamespace
2、避免使用using
引入整个命名空间的标识符号
// 禁止 —— 污染命名空间
using namespace mynamespace;
3、避免进行大量构造及析构操作
for (int i = 0; i < 10000; i++) {Timer t; // 低效,构造函数和析构函数分别调用10000次t.DoSomething(i);
}
建议使用以下代码:
Timer t; // 构造函数和析构函数只调用1次
for (int i = 0; i < 10000; i++) {t.DoSomething(i);
}
4、尽量在变量声明时进行初始化,且避免进行无效的初始化
int i;
i = f(); // 坏 —— 声明与初始化分离
int j = g(); // 好 —— 声明时初始化int k = 0; // 坏 —— 无效初始化
k = 0xff;
5、尽量避免全局函数和全局变量,使用命名空间或static
关键字等进行作用域限制
6、禁止定义静态储存周期非POD变量
静态存储周期变量,即包括了全局变量、静态变量、静态类成员变量和函数静态变量,都必须是原生数据类型(POD:Plain Old Data):即int
、char
和float
,以及POD类型的指针、数组和结构体。
禁止使用类的静态存储周期变量,即禁用vector
和string
等:由于构造和析构函数调用顺序的不确定性,它们会导致难以发现的bug。不过constexpr
变量除外,因为它不涉及动态初始化和析构。
类
1、不要在构造函数和析构函数中调用虚函数
如果在派生类的构造函数和析构函数中调用了虚函数,这类调用不会重定向到派生类的虚函数实现。
2、不要在无法报出错误时进行可能失败的初始化
如果代码允许,直接终止程序是一个合适的处理错误方式。否则,可以考虑用Init()
方法或工厂函数。
3、建议使用初始化列表构造对象,且和构造函数、析构函数一样放在类外实现
使用初始化列表构造对象,比起构造函数的代码块初始化效率更高、性能更好。
// a.h
class A
{public:A() : {};
private:int m_a;B* m_b;
};// a.cpp
A::A() : m_a(0), m_b(nullptr) {}
4、不要定义隐式转换类型
对于转换运算符和单参数构造函数,建议使用explicit
关键字。
举例如下:
class Things
{public:explicit Things(const std::string &name = "") :m_name(name), m_height(0), m_weight(0) { }int CompareTo(const Things &other);
private:std::string m_name;int m_height;int m_weight;
};
这里的构造函数用explicit
关键字来防止隐式类型转换。
Things a;
std::string s = "book";
int ret = a.CompareTo(s); // 坏 —— 存在隐式转换,在"explicit"关键字的防护下将会报错
int ret = a.CompareTo(Things(s)); // 好
5、拷贝构造函数和拷贝赋值运算符,移动构造函数和移动赋值运算符成套使用,如果不需要,则将它们显式地禁用
如果类型可拷贝,则需要同时给出拷贝构造函数和拷贝赋值运算符的定义。
// 拷贝构造函数
MyClass(const MyClass &t)
{if (this == &t) return;if (t.text == nullptr) return;int len = strlen(t.text);text = new char[len + 1];strcpy(text, t.text);
}
// 拷贝赋值运算符
MyClass &operator = (const MyClass &t)
{if (this == &t) return *this;if (text != nullptr) {free(text);text = nullptr;}if (t.text == nullptr) return *this;int len = strlen(t.text);free(text);text = new char[len + 1];strcpy(text, t.text);return *this;
}
同理,如果类型可移动,则需要同时给出移动构造函数和移动赋值运算符的定义。
由于存在对象切割的风险,不要为任何有可能有派生类的对象提供赋值操作或者拷贝 / 移动构造函数(当然也不要继承有这样的成员函数的类)。如果你的基类需要可复制属性,请提供一个public virtual Clone()
和一个protected
的拷贝构造函数以供派生类实现。
如果你的类不需要拷贝 / 移动操作,请显式地通过在public
域中使用= delete
或DISALLOW_COPY_AND_ASSIGN
禁用之。
方法一:
class MyClass
{public:MyClass(char *text);~MyClass();MyClass(const MyClass &) = delete;MyClass &operator = (const MyClass &) = delete;
private:char *m_text;
}
方法二:
#define DISALLOW_COPY_AND_ASSIGN(MyClass) \MyClass(const MyClass &); \MyClass &operator = (const MyClass &)class MyClass
{public:MyClass(char *text);~MyClass();
private:DISALLOW_COPY_AND_ASSIGN(MyClass);char *m_text;
}
6、仅当只有数据成员时使用struct
,其它一概使用class
7、优先考虑使用组合,其次是继承
不要过度使用继承,组合常常更合适一些。尽量做到只在“是一个”,而非“有一个”的情况下使用继承。
8、仅使用public
继承
所有继承必须是public
的,如果想使用私有继承,则应该替换成把基类的实例作为成员对象的方式。
9、如果类有虚函数,则析构函数也应该为虚函数
在声明重载时,请使用override
、final
或virtual
的其中之一进行标记。
10、尽量不要重载运算符,也不要创建用户定义字面量
但不要为了避免重载操作符而走极端。比如,应当定义==
、=
和<<
,而不是Equals()
、CopyFrom()
和PrintTo()
。
11、将所有数据成员声明为private
,除非是static const
类型成员
这么做的原因是要求对数据成员进行存取控制。
12、将相似的声明放在一起,将public
部分放在最前
类定义一般应以public:
开始,后跟protected:
,最后是private:
。
在各个部分中,建议将类似的声明放在一起,并且建议以如下的顺序:类型(包括typedef
、using
和嵌套的结构体与类)、变量、工厂函数、构造函数、赋值运算符、析构函数、其他函数、数据成员。
函数
1、编写简短、凝练、功能单一的函数,尽量不要写超过 100 行的函数
如果函数超过 100 行,可以考虑在不影响程序结构的前提下对其进行分割。
2、不同函数中的重复代码应该尽可能提炼成单一的函数
3、避免函数的代码嵌套过深,尽量低于 5 层
嵌套深度,指函数中的代码控制块(如if
、for
、while
、switch
等)之间互相包含的深度。嵌套过深将导致代码的阅读成本增加。
4、函数的参数应该尽量不超过 5 个
5、废弃代码应及时清理
可以使用注释括起现在暂未使用而将来可能使用的代码,但废弃代码更应当被清除。
6、将所有输入参数放在所有输出参数之前
需要注意的是,在加入新参数时不要因为它们是新参数就置于参数列表最后,而是仍然要按照该规则,即将新的输入参数也置于输出参数之前。
7、所有按引用传递的参数必须加上const
函数参数列表中,所有引用参数都必须是const
。如果一个参数有被改变的可能,则建议使用指针。
8、尽量使用const
对声明的变量或参数进行限制
尽量使用const
,将会提升代码的健壮性。
在类的set
方法中,当输入参数为简单类型,则不需要添加const;当输入参数为容器时,使用const &
可提高性能。
void set_float(float var);
void set_string(const std::string &str);
void set_things(const std::vector<std::string> &vec);
在类的get
方法中,其后加const
表明该函数为只读函数;当输出参数为容器时,使用const &
可提高性能,且此时返回值不可被修改。
float get_float() const;
const std::vector<std::string> &get_things() const;
9、只允许在非虚函数中使用缺省参数,且必须保证缺省参数的值始终一致
对于虚函数,不允许使用缺省参数,因为在虚函数中缺省参数不一定能正常工作。如果在每个调用点缺省参数的值都有可能不同,在这种情况下缺省参数也不允许使用。
void Func(int n = counter++); // 错误 —— 缺省参数存在变更
10、避免野指针的产生
指针变量在声明时,就应该进行初始化赋值(nullptr
或准确的地址,不建议使用NULL
)。
指针在释放后,且生命周期暂未终结时,需要置空(nullptr
,不建议使用NULL
)。
11、建议使用auto
绕过繁琐的类型名,且仅在局部变量使用
12、内联函数应该尽量短
关键字inline
必须与函数定义放在一起才能使函数成为内联函数,仅仅将inline
放在函数声明前面不起任何作用。
内联函数应该尽可能短,原则上不允许超过 10 行的内联函数。
命名
在了解命名规则前,首先需要了解几种命名法。
小驼峰命名法
命名的第一个单词以小写字母开始,第二个单词开始以后的每个单词的首字母都采用大写字母。且单词之间无下划线连接,如firstName
、lastName
。这样的命名看上去就像骆驼峰一样此起彼伏,故得名。
大驼峰命名法
又名“帕斯卡命名法”,与小驼峰命名法类似,但每个单词的首字母均大写。如FirstName
、LastName
。
匈牙利命名法
基本结构是:属性 + 类型 + 具体描述。如uiNum
、pTimer
、strName
、g_pSource
。
属性部分:
g_ 全局变量
c_ 常量
m_ 类成员变量
s_ 静态变量
类型部分:
c char
b bool
i/n int
u unsigned
f float/file
d double
l long
h handle
fn 函数
p 指针
str string
下划线命名法
命名的每个单词用下划线隔开,且每个单词均小写。如first_name
、last_name
。
1、尽可能使用描述性的命名,不要使用含糊不清的缩写
2、所有类型名称使用大驼峰命名法
所有类型包括:类、结构体、类型定义(typedef)、枚举、类型模板参数。
// 类和结构体
class UrlTable
{ ...
struct UrlTableProperties
{ ...// 类型定义
typedef hash_map<UrlTableProperties *, string> PropertiesMap;// using 别名
using PropertiesMap = hash_map<UrlTableProperties *, string>;// 枚举
enum UrlTableErrors
{ ...
3、变量使用下划线命名法,且类的成员变量以m_
开头
// 变量
string table_name;// 类的成员变量
class TableInfo
{...
private:string m_table_name;
};// 结构体变量
struct UrlTableProperties
{string table_name;
};
4、常量使用小驼峰命名法,且以k
开头
常量,即声明为constexpr
或const
的变量。
const int kDaysInAWeek = 7;
5、函数使用大驼峰命名法或下划线命名法
一般来说,相对于一个功能模块而言,模块外有可能会调用到的函数(即对外API),命名应该使用大驼峰命名法。而模块内部调用的函数,命名应该使用下划线命名法。
6、命名空间使用下划线命名法
namespace gbtimer_verilog
{ ...
7、宏的命名使用全大写,并且可以使用下划线
#define PI_ROUNDED 3.0
8、枚举的命名应当和常量或宏一致,且枚举的第一个值应当为默认值或无效值
具体使用哪种,视项目内已有代码而定。
// 和常量一致
enum UrlTableErrors
{kOK = 0, // 默认值kErrorOutOfMemory,kErrorMalformedInput,
};
// 和宏一致
enum AlternateUrlTableErrors
{OK = 0, // 默认值OUT_OF_MEMORY = 1,MALFORMED_INPUT = 2,
};
注释
1、函数声明处的注释描述函数功能,定义处的注释描述函数实现
但同时也要避免对显而易见的内容进行注释
2、对那些临时的、短期的解决方案,或需要补充的代码使用TODO
注释
格式
每个人都可能有自己的代码风格和格式,但如果一个项目中的所有人都遵循同一风格的话,这个项目就能更顺利地进行。每个人未必能同意下述的每一处格式规则,而且其中的不少规则需要一定时间的适应,但整个项目服从统一的编程风格是很重要的,只有这样才能让所有人轻松地阅读和理解代码。
1、每一行代码字符数尽量不要超过 80
2、避免产生超过 3000 行的超大文件
3、使用空格缩进,不要使用制表符,且每级缩进为 2 个空格
4、相对独立的程序块之间建议添加空行
5、返回类型和函数名在同一行,参数也尽量放在同一行,如果放不下就对形参分行
ReturnType ClassName::ReallyLongFunctionName(Type par_name1,Type par_name2, Type par_name3)
{DoSomething();...
}
或者:
ReturnType ClassName::ReallyLongFunctionName(Type par_name1,Type par_name2,Type par_name3)
{DoSomething();...
}
6、if
、for
、do
、while
、switch
、case
、default
等语句与{
在同一行,而}
独占一行
if (condition) { // 圆括号里没有空格,左大括号紧随其后... // 2 空格缩进
} else if (...) { // else 与 if 的右大括号同一行...
} else {...
} // 右大括号独占一行if (x == kFoo) return new Foo(); // 简短的条件语句允许写在同一行,且省略大括号
switch (var) {case 0: { // 2 空格缩进... // 4 空格缩进break;}case 1: {...break;}default: {...}
}
while (condition) {// 反复循环直到条件失效.
}for (int i = 0; i < kSomeNumber; ++i) {...
}int i = 0;
// 注意留白
for ( ; i < kSomeNumber; ) {...++i;
}
7、->
、.
、指针/地址操作符*
与&
前后不加空格
x = *p;
p = &x;
x = r.y;
x = r->y;
8、在声明指针变量或参数时,建议*
与&
紧挨变量名。
// 空格前置,建议统一为此种
char *c;
const string &str;// 空格后置,也可以
char* c;
const string& str;
9、一个表达式换行时,操作符总位于行尾
if (this_one_thing > this_other_thing &&a_third_thing == a_fourth_thing &&yet_another && last_one) {...
}
10、不要在return
表达式里加上非必须的括号
return result; // 没有圆括号
return (result); // 差 —— 圆括号没有实际意义
return (some_long_condition && another_condition); // 用圆括号改善可读性
11、预处理指令不要缩进,从行首开始
if (lopsided_score) {#if DISASTER_PENDING // 好 —— 指令从行首开始,且 # 与 if 之间没有空格DropEverything();
#endifBackToNormal();}
12、访问控制快的声明依次序是public:
、protected:
、private
,且不进行缩进
class MyClass : public OtherClass
{public: // 注意有一个空格的缩进MyClass(); // 标准的两空格缩进explicit MyClass(int var);~MyClass() {}void SomeFunction();int get_var() const { return m_var; }private:int m_var;
};
13、命名空间、函数、类、结构体、联合体的{
与}
均另起一行,枚举视长短而定
struct config_rule
{ // { 另起一行char *name;union{ // { 另起一行int i;double d;}; // } 另起一行
}; // } 另起一行// 较长的枚举
enum config_type
{CONFIG_TYPE1,CONFIG_TYPE2,...
};
// 较短的枚举
enum num_type { NUM_TYPE1, NUM_TYPE2 };
14、水平留白
水平留白使用根据在代码中的位置决定,但永远不要在行尾添加没意义的留白。
// 置于右边的注释与注释的内容之间有 1 个空格// 列表初始化中大括号内的空格是可选的
// 如果加了空格, 那么两边都要加上
int x[] = { 0 };
int x[] = {0};x++; // 一元运算符与参数之间没有空格
v = w * (x + z); // 二元运算符前后均有空格
x = a > b ? a : b; // 三元运算符前后均有空格// 尖括号不与空格紧邻,< 前没有空格,> 和 ( 之间也没有
vector<string> x;
y = static_cast<char *>(x);// 函数入参之间用 , 和空格隔开
void func(int a, int b);
15、垂直留白
基本原则是:同一屏可以显示的代码越多,越容易理解程序的控制流。当然,过于密集的代码块和过于疏松的代码块同样难看,这取决于你的判断。但通常是垂直留白越少越好,且函数体首尾不要留空行,不要有连续的空行。
编译
1、程序编译时产生的所有warning
都应该被修复
特殊的,LEX与YACC产生的移进-归约冲突及归约-归约冲突视情况而定,但原则上所有告警都应该被修复。
C++编程规范(参考Google、华为)相关推荐
- 基于华为Java编程规范的Eclipse checkStyle.xml
发现项目组成员代码规范存在较大的问题,于是就在华为编程规范的基础上制定了这份checkStyle.xml文档,至于Eclipse怎么安装checkStyle插件以及该插件怎么使用请自行Google之. ...
- 编程规范学习资料清单
资料清单包括: 1. c C软件编程规范总则.lwp 华为C编程规范 2. c# 华为C#编码规范 3. c++ C++编程规范 C++编程规范_1(排版) C++ ...
- C语言编程规范学习笔记和总结(附华为编程规范机试参考试题)
目录 规范说明 一.头文件 原则1.1 头文件中适合放置接口的声明,不适合放置实现. 原则1.2 头文件应当职责单一 原则1.3 头文件应向稳定的方向包含 规则1.1 每一个.c文件应有一个同名.h文 ...
- 编程规范 (百度、华为)
1 华为 Java 编程规范 1.1 排版 1.1.1 规则 规则1 . 程序块要采用缩进风格编写,缩进的空格数为4个,不允许使用TAB缩进. 说明:缩进使程序更易阅读,使用空格缩进可以适应不同操作系 ...
- 华为C语言编程规范重点笔记(学习C编程规范看这篇就够了)
华为C编程规范原文详情:link. 一.代码总体原则 1.清晰第一 **清晰性是易于维护.易于重构的程序必需具备的特征.**"程序必须为阅读它的人而编写,只是顺便用于机器执行".& ...
- 华为编程规范_华为 Java 编程规范出炉,究竟和官方文档有何不同?
来源:blog.csdn.net/chenleixing/article/details/44173985 1.引言 这个标准是衡量代码本身的缺陷,也是衡量一个研发人员本身的价值.华为作为一家全球化的 ...
- 华为c语言编程规范_C语言编程规范
一.简介 代码编写规则应该在建立一个工程项目之前,应该贯穿整个项目的始终,以保证代码的一致性.采用标准的代码编写惯例,可以大大简化项目的维护负担.采用一种好的风格,以达到以下目的:可移植性.连贯.整洁 ...
- 【读书笔记】-《华为-C语言编程规范》
前言 作为程序开发者,避免不了阅读别人代码,那么就会涉及到到一门语言的编程规范.规范虽然不是语言本身的硬性要求,但是已经是每一个语言使用者约定俗成的一个规范.按照编程规范编写的代码,至少在代码阅读时, ...
- 《华为C语言编程规范 》笔记
title: <华为C语言编程规范 > data: 2021-11-7 第一章 排版 相对独立的程序块之间.变量说明之后必须加空行. if.for.do.while.case.switch ...
- 华为python语言通用编程规范 模块导入顺序_Python编程规范
1,Python编程规范 > 编码 所有的 Python 脚本文件都应在文件头标上 #-*- coding:utf-8 -*- 用于设置编辑器,默认保存为 utf-8 格式. > 注释 业 ...
最新文章
- 深度学习实现场景字符识别模型|代码干货
- mysql中添加外键属性_Python将值插入外键属性(MYSQL)
- Linux使用百度云
- Python 大括号和百分号
- Android开发学习笔记:Gallery和GridView浅析
- mfc指示灯报警显示_消防水炮需要外置声光报警吗
- mysql可以运行在不同sql mode模式下面,sql mode模式定义了mysql应该支持的sql语法,数据校验等...
- 为什么借钱要上央行征信?
- matlab变量由非标量,matlab中的if语句
- [结构力学] 几何构造分析的技巧
- 使用IronPython集成Python和.NET
- 何如添加到将文章添加到首页
- Firefox恢复书签
- 服务器虚拟化太金苹果效果好,《我的世界》金苹果更新速度太快,如今附魔金苹果“可遇不可求”...
- 几种投影的特点及分带方法
- 奥迪坚技术革新带动信用卡呼叫中心管理升级
- python绘制散点图运行结果是_用python绘制散点图
- php files 转数组,转 PHP文件上传$_FILES数组各键值含义说明
- 在线引流工具Tcpcopy原理、使用、采坑
- 2022-2028全球与中国Oracle Bronto咨询服务市场现状及未来发展趋势
热门文章
- Vscode markdown 添加、粘贴、导入图片
- 网安之php开发第十七天
- 网页在线自动回复客服源码
- kali安装中文拼音googlepinyin之坑
- Python爬虫学习笔记 (9) [初级] 小练习 爬取慕课网课程清单
- 【方向盘】因“双减”失业,厉经9面,终获美团外卖L8的Offer
- 西密歇根大学计算机科学专业排名,西密歇根大学有哪些专业_专业排名(USNEWS美国大学排名)...
- 自我修炼是优秀领导者的最高层次--张一鸣
- 垃圾分类查询小程序(可回收物、有害垃圾、干垃圾、湿垃圾)
- 基于java的水费管理系统