首页 > 编程语言 >Google C++编程规范(Google C++ Style Guide)

Google C++编程规范(Google C++ Style Guide)

时间:2023-09-03 16:56:29浏览次数:45  
标签:Style Google 头文件 函数 代码 C++ 注释 变量 定义

参考链接:
Google 代码规范 C++总结
Google 开源项目风格指南——中文版

Google C++ Style Guide是一份不错的C++编码指南,我制作了一张比较全面的说明图,可以在短时间内快速掌握规范的重点内容。不过规范毕竟是人定的,记得活学活用。看图前别忘了阅读下面两条重要建议:

  1. 保持一致也非常重要,如果你在一个文件中新加的代码和原有代码风格相去甚远的话,这就破坏了文件本身的整体美观也影响阅读,所以要尽量避免。
  2. 一些条目往往有例外,比如下面这些,所以本图不能代替文档,有时间还是把PDF认真阅读一遍吧。
  • 异常在测试框架中确实很好用
  • RTTI在某些单元测试中非常有用
  • 在记录日志时可以使用流
  • 操作符重载 不提倡使用,有些STL 算法确实需要重载 operator== 时可以这么做

sibGL7

1.概述

对于高质量的工程,一般会做到:

  1. 代码简洁精炼,美观,可读性好,高效率,高复用,可移植性好,高内聚,低耦合,没有冗余,不符合这些原则,必须特别说明。

  2. 规范性,代码有规可循。特殊排版、特殊语法、特殊指令,必须特别说明。

2.文件排版

2.1.包含头文件

  • a)系统头文件与用户头文件包含区分开,不交叉。

  • b)系统头文件,稳定的目录结构,应采用包含子路径方式。#include”sub/test.h”

  • c)系统头文件应用:#include

  • d)自定义同文件应用:#include "xxx.h"

  • e)只引用需要的头文件。

  • f)将所有#include的文件名视为大小写敏感。能使用声明的情况下,使用声明。

2.2. h和cpp文件

  • a)头文件命名为.h,内联文件命名为.inl;C++文件命名为*.cpp

  • b)文件名用不要用无意义的名称:例如XImage.cpp,命名方式在系统中应该统一。

  • c)头文件除了特殊情况,应使用#ifdef控制块。

  • d)头文件#endif应采用行尾注释。

  • e)头文件,首先是包含全局函数,其次是宏定义代码块,然后是全局变量,全局常量,类型定义,类定义,内联部分。

  • f)cpp文件,包含指令,宏定义,全局变量,函数定义。

2.3.文件结构

  • a)文件应包含文件头注释和内容。

  • b)函数体类体之间原则上用1个空行,特殊情况下可用一个或者不需要空行。

2.4.空行

文件头、控制块,#include部分、宏定义部分、class部分、全局常量部分、全局变量部分、函数和函数之间,用一个空行。'


3.注释方面

3.1.文件头注释

作者,文件名称,文件说明,生成日期(可选),提供模板

3.2.函数注释

  • a)关键函数必须写上注释,说明函数的用途,提供注释模板。

  • b)特别函数参数,需要说明参数的目的,由谁负责释放等等。

  • c)除了特别情况,注释写在代码之前,不要放到代码行之后。

  • d)对每个#else或#endif给出行末注释。

  • e)关键代码注释,包括但不限于:赋值,函数调用,表达式,分支等等。

  • f)尚未实现完整的代码,或者需要进一步优化的代码,应加上 // TODO ...或者同等含义的注释。

  • g)调试的代码,加上注释 // DEBUG或者同等含义的注释

  • h)需要引起关注的代码,加上注释 // NOTE ...或者同等含义的注释

  • i)对于较大的代码块结尾,如for,while,do等,可加上 // end for|while|do或者同等含义的注释。


4.命名方面

4.1.原则

  • a)同一性:在编写一个子模块或派生类的时候,要遵循其基类或整体模块的命名风格,保持命名风格在整个模块中的同一性。

  • b)标识符组成:标识符采用英文单词或其组合,应当直观且可以拼读,可望文知意,用词应当准确,避免用拼音命名。

  • c)最小化长度 && 最大化信息量原则:在保持一个标识符意思明确的同时,应当尽量缩短其长度。

  • d)避免过于相似:不要出现仅靠大小写区分的相似的标识符,例如"i"与"I","function"与"Function"等等。

  • e)避免在不同级别的作用域中重名:程序中不要出现名字完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但容易使人误解。

  • f)正确命名具有互斥意义的标识符:用正确的反义词组命名具有互斥意义的标识符,如:"minValue" 和 "maxValue","getName()" 和"setName()" ….

  • g)避免名字中出现数字编号:尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。

4.2.函数

  • a)类的函数名称应采用首字母小写类似handleXXX命名,例如:handleColor;不推荐采用例如 HandleColor;除了标准c风格代码,标准模板库,不推荐用下划线,例如,handle_color。容易与系统函数标准函数重名,导致不能目视而知其作用范围。

  • b)函数参数比较多时,应考虑用结构代替,参数不能超过6个。

  • c)如果不能避免函数参数比较多,应在排版上可考虑相似含义的参数占用一行,参数名竖向对齐。甚至每个参数一行。

4.3.变量

a)变量命令方式应采用驼峰命令方式。例如handleColor;不同类型变量打头方式见表 1,当类型叠加时,应以最能够表现变量类型的打头方式,例如int类型的指针,应采用p打头;指针类型的数组,应采用a打头,数组的指针因采用p打头。

表 1 变量类型打头表

类型 打头 备注
int n 如nValue
bool b
long l 如lValue
float f
double d
std::string/QString str
std::list/QList lst 如lstValues
std::vector/QVector vec
std::map/QMap map
枚举 e
指针 p
引用 r
数组 a

b)不同作用范围的变量应在类型前面添加前缀加下划线,不同作用范围的前缀见表 2。

表 2变量作用范围前缀表

类型 前缀 备注
成员变量 m_ 如m_nValue
全局变量 g_ 如g_lValue
静态变量 s_ 如s_pValuePtr,静态全局和静态成员也应s为前缀

4.4.类型名

  • a)类名和结构体首字母大写,例如MyClass,MyStruct。

  • b)类和对象名应是名词。

  • c)枚举定义以E_打头,且应全大写,使用下划线分割不同的引文单词,如E_TYPE_STUDENT_INFO,各枚值名字应为枚举类型名打头,例如E_TYPE_STUDENT_INFO_NUMBER。

  • d)宏定义以DEF_打头,且应全大写,使用下划线分割不同的引文单词,如DEF_TYPE_ID。


4.5.风格兼容性

a)对于移植的或者开源的代码,可以沿用原有风格,不用C++的命名规范。


5.1.Tab和空格

  • a)每一行开始处的缩进只能用4个空格,不能用Tab,输入内容之后统一用空格。

  • b)在代码行的结尾部分不能出现多余的空格。

  • c)不要在"::","->","."前后加空格。

  • d)不要在",",";"之前加空格。

5.2.类型定义

  • a)类,结构,枚举,联合:大括号另起一行

  • b)函数体的{需要新起一行,在{之前的缩进应与上一级对齐。

  • c)除了特别情况,函数体内不能出现两个空行。

  • d)除了特别情况,函数体内不能宏定义指令,除非该宏定义仅能在该函数内使用。

  • e)在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。

5.3.代码块

  • a)"if"、"for"、"while"、"do"、"try"、"catch" 等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 "{ }" 。这样可以防止书写和修改代码时出现失误。

  • b)"if"、"for"、"while"、"do"、"try"、"catch" 的括号和表达式,括号可紧挨关键字,这样强调的是表达式。

5.4.代码行

  • a)一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。

  • b)多行变量定义,为了追求代码排版美观,可将变量竖向对齐。

  • c)代码行最大长度宜控制在一定个字符以内,能在当前屏幕内全部可见为宜。建议80个。

5.5.宏

  • a)不要用分号结束宏定义。

  • b)能使用函数来解决的问题,不要使用宏,方便调式。

5.6.goto

  • a)不要用goto。

6.类型

  • a)定义指针和引用时*和&紧跟变量名。

  • b)尽量避免使用浮点数,除非必须。

  • c)用typedef简化程序中的复杂语法。

  • d)避免定义无名称的类型。例如: enum TState { EIdle, EActive };

  • e)少用union,如果一定要用,则采用简单数据类型成员。

  • f)用enum取代(一组相关的)常量。

  • g)不要使用魔鬼数字。

  • h)尽量用引用取代指针。

  • i)定义变量完成后立即初始化,勿等到使用时才进行,在需要使用到变量的时候才定义变量。

  • j)如果有更优雅的解决方案,不要使用强制类型转换。例如dynamic_cast,尽量使用多态。


7.表达式

  • a)避免在表达式中用赋值语句。

  • b)避免对浮点类型做等于或不等于判断。

  • c)不能将枚举类型进行运算后再赋给枚举变量。

  • d)在循环过程中不要修改循环计数器。

  • e)检测空指针,用 if( p )

  • f)检测非空指针,用 if( ! p )


8.函数

8.1.引用

  • a)引用类型作为返回值:函数必须返回一个存在的对象。

  • b)引用类型作为参数:调用者必须传递一个存在的对象。

8.2.返回值

  • a)除开void函数,构造函数,析构函数,其它函数必须要有返回值。在函数的实现中,每个分支必须显示返回return。

  • b)当函数返回引用或指针时,用文字描述其有效期。

8.3.内联函数

  • a)内联函数应将函数体放到类体外。

  • b)只有简单的函数才有必要设计为内联函数,复杂业务逻辑的函数不要这么做。

  • c)虚函数不要设计为内联函数。

8.4.函数参数

  • a)只读取该参数的内容,不对其内容做修改,用常量引用。

  • b)修改参数内容,或需要通过参数返回,用非常量引用。

  • c)简单数据类型用传值方式。

  • d)复杂数据类型用引用或指针方式。

  • e)输入参数排在前面,输出参数排在后面,默认参数除外。

  • f)除通用库函数,尽量不使用默认参数。


9.类

9.1.整体结构

  • a)按照 public, protected, private 的顺序分块。哪一块没有,就直接忽略。

  • b)每一块中,按照下面顺序排列

1)typedef,enum,struct,class 定义的嵌套类型

2)常量

3)构造函数

4)析构函数

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

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

  • c).cpp 文件中,函数的实现尽可能和声明次序一致。

9.2.构造函数

  • a)构造函数的初始化列表,应和类里成员变量的顺序一致。

  • b)初始化列表中的每个项,应独占一行。

  • c)避免出现用一个成员初始化另一个成员。

  • d)构造函数应初始化所有成员,尤其是指针。

  • e)不要在构造函数和析构函数中抛出异常。

9.3.纯虚函数

接口类的虚函数应设计为纯虚函数。

9.4.构造和析构函数

  • a)如果类可以继承,则应将类析构函数设计为虚函数。

  • b)如果类不允许继承,则应将类析构函数设计为非虚函数。

  • c)如果类不能被复制,则应将拷贝构造函数和赋值运算符设计为私有的。

  • d)如果为类设计了构造函数,则应有析构函数。

9.5.成员变量

  • a)尽量避免使用mutable(mutex除外)和volatile。

  • b)尽量避免使用公有成员变量。

9.6.成员函数

  • a)努力使类的接口少而完备。

  • b)尽量使用常成员函数代替非常量成员函数,const函数

  • c)除非特别理由,绝不要重新定义非虚函数。

  • d)如果是子类型重写父类的虚函数,应该在函数声明后面添加override,让编译器来检查是否重新定义非虚函数。C++11

  • e)不想被子类重写的虚函数,函数声明后面添加final。C++11

9.7.继承

  • a)继承必须满足IS-A的关系,HAS-A应采用包含。

  • b)虚函数不要采用默认参数。

  • c)除非特别需要,应避免设计大而全的虚函数,虚函数功能要单一。

  • d)除非特别需要,避免将基类强制转换成派生类。

10.错误处理

  • a)释放内存完成后将指针赋空,避免出现野指针。

  • b)使用指针前进行判断合法性,应考虑到为空的情况的处理,除非明显的组合模式。

  • c)使用数组时,应先判断索引的有效性,处理无效的索引的情况。

  • d)卫句风格:先处理所有可能发生错误的情况,再处理正常情况。


11.性能

  • a)头文件中使用前向声明代替头文件包含。Class M;

  • b)尽量在for循环之前,先写计算估值表达式。

  • c)尽量避免在循环体内部定义对象。

  • d)避免对象拷贝,尤其是代价很高的对象拷贝。

  • e)避免生成临时对象,尤其是大的临时对象。

  • f)注意大尺寸对象数组。

  • g)尽量使用标准库中封装的算法。

标签:Style,Google,头文件,函数,代码,C++,注释,变量,定义
From: https://www.cnblogs.com/RioTian/p/17675173.html

相关文章

  • C/C++ const关键字 解读
    Thecollocationbetweenconstandoriginalpointerisconfusedtomanypeople.Therearetwousagesofit.Thefirstoneisavariablepointerthatpointsaconstantdata.i.e.constint*p#include<iostream>intmain(){ inta=1,b=2; const......
  • C++算法之旅、05 基础篇 | 第二章 数据结构
    常用代码模板2——数据结构-AcWing笔试用数组模拟而不是结构体使用结构体指针,newNode()非常慢,创建10万个节点就超时了,做笔试题不会用这种方式(优化是提前初始化好数组,但这样跟数组模拟没区别了,而且代码量很长)单链表(数组)使用两个数组,e存储val,ne存储next。空节点next用-1表......
  • 《C++并发编程实战》读书笔记(2):线程间共享数据
    1、使用互斥量在C++中,我们通过构造std::mutex的实例来创建互斥量,调用成员函数lock()对其加锁,调用unlock()解锁。但通常更推荐的做法是使用标准库提供的类模板std::lock_guard<>,它针对互斥量实现了RAII手法:在构造时给互斥量加锁,析构时解锁。两个类都在头文件<mutex>里声明。std::......
  • msvc++中的预编译头文件pch.hpp和stdafx.h
    预编译头文件在VisualStudio中创建新项目时,会在项目中添加一个名为pch.h的“预编译标头文件”。(在VisualStudio2017及更高版本中,该文件名为stdafx.h)此文件的目的是加快生成过程。应在此处包含任何稳定的标头文件,例如标准库标头(如)。预编译标头仅在它或它包含的任何......
  • C++引用
    首先引用是什么?在教程里说引用就是起别名。在我学过这一部分后觉得引用其实就是属于指针,有点像是指针的语法缩写。怎么说呢,我认为就两点三种传递引用是什么,引用的本质1、三种传递值传递不改变实参,地址传递和引用传递改变实参1#include<iostream>2usingnamespaces......
  • 如何使用C++11原子操作实现自旋锁
    什么是自旋锁?C++自旋锁是一种低层次的同步原语,用于保护共享资源的访问。自旋锁是一种轻量级的锁,适用于短时间的资源锁定。自旋锁的特点:当一个线程尝试获取已经被另一个线程占有的自旋锁时,这个线程会进入一个循环(自旋),在这个循环中它不断地检查锁是否已经被释放。如果锁已经被释放,那......
  • C++的基类和派生类构造函数
    基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。在设计派生类时,对继承过来的成员变量......
  • c++ 堆排序
    堆排序主要分为两个函数:1、构建堆2、元素调整#include<iostream>usingnamespacestd;voidmaxHeap(inttree[],intn,inti){ if(i>=n) return; intlchild=i*2+1; intrchild=i*2+2; intmax=i; if(lchild<n&&tree[lchild]>t......
  • C++ Core Guidelines解析 电子书 pdf
    关注公众号:红宸笑。回复:电子书即可  在《C++CoreGuidelines解析》中,C++专家讲师RainerGrimm提炼出了CoreGuidelines中的精髓,去除了晦涩难懂的内容,分享了新的见解和背景,并提供了自己培训课程中经过充分测试的示例。对于使用C++11及后续版本C++的有经验程序员,G......
  • C++刷题输入输出和常用函数处理
    1.输入数字但非默认的十进制,比如输入的是十六进制数,但要转为十进制再进行别的处理。当我们在编程中处理十六进制数时,通常会将其表示为字符串。cin>>hex>>m;//输入十六进制,m会自动转十进制。2.int和string中单个字符互转strings="12345";inta0=s[0]-'0';//字符转......