QT/C++编程规范

前言

    这是自己整理出的一套自己正在使用的编程规范,并没有涵盖有所东西,只有一些自己常用或正在使用的,后面也许会继续添加新用到规范。此规范更偏向于java,借鉴了google、qt、llvm和java相关的编程规范。
    由于我自己更希望能够写出面向接口的编程,所以这里先说一下自己对接口和抽象类的理解和在C++中的定义方式:
       - 接口:只有纯虚函数的类称为接口。接口是对行为的抽象,用于描述某一实体所拥有的行为。
       - 抽象类:至少拥有一个纯虚函数并继承至QObject的类称为抽象类。抽象类是对功能的抽象,而对行为的实现。
    抽象类中的纯虚函数也许并不是必要的,这里只是不希望被实例化。这里关于抽象类的定义其实也只是我看别人源码所感悟出的,目前本人也基本按照这个模板在撸代码。一般我会定义一个或一系列抽象类去实现某些接口,抽象类中会对这些行为定义一些实现步骤并对步骤中的功能进行抽象,抽象类的子类去对具体功能进行实现。也就是说某一个抽象类的子类的同一个行为的实现步骤一定是相同的,不同的是步骤中的功能细节,如果对同一行为有不同的实现步骤,那么需要实现不同的抽象类。举个例子:

人有吃饭的行为,而同样的东方人都是使用筷子吃饭,假设人是机械化的拿到筷子,并循环夹菜、吃菜、吃饭,那么这个过程就应该是抽象类去实现,而具体怎么夹菜、夹多少量可能对于不同阶级的人有不同的定义方式,那么就应该由子类去实现。
东方人和西方人都有吃饭的行为,但是西方人用的是刀叉,那么他们吃饭的过程应该是拿到刀叉,并循环切菜、吃菜。那么这个时候就需要重新定义一个抽象类去实现这个行为。

    上面这个例子也许并不是特别的恰当,毕竟人吃饭这个行为实在是太多元化,需要用更复杂的方式去定义,如果不能理解的话就自行搜索一下接口和抽象类的定义,毕竟这里不是专门讲这个的,只是提出个人的理解抛砖引玉一下。


正文

  1. 变量的定义不要加莫名其妙的前缀,直接以英文单词即可,bool类型统一使用is作为前缀,第一个单词全小写,第二个单词开始首字母大写,不要使用下划线,如:int num = 0; bool isOk = false;变量名尽量长而全,不要乱用简写或者a、b、c作为变量名。
  2. 类属性的定义有两种形式:
        我在测试代码中通常将类属性定义在头文件中,并以m_作为前缀,后面参考变量的定义,类属性的初始化使用大括号,如int m_num{0}; bool m_isOk{false};
        常规代码中我通常使用QT4的属性定义形式,在cpp文件中定义一个结构体,结构体名为"类名+Data",结构体中定义该类的属性,参考变量的定义,不加前缀,在头文件中前置声明该结构体,并使用"类名+Data" *d;的形式定义:
    .h
struct AppData;
class App
{
private:
    AppData *d;
};

.cpp

struct AppData
{
    int num{0};
    bool isOk{false};
};
  1. 函数的定义和变量一样,唯一需要注意的是bool类型的setter是setOk而不是setIsOk。getter采用的是QT的形式,直接以属性名作为函数名int num(),而不是getNum()。
  2. 函数、类、结构体的大括号应该放在新的一行(参考第二条中类和结构体的定义),其他大括号,如枚举、命名空间、if、for等应该放在名字的同一行(这主要是想让一个电脑屏幕能够显示更多的代码):
enum E {
    e
};
if (a == 1) {
    
}
  1. 其他语言不说,C++中禁止使用异常(问就是不好用),并且除析构函数以外的其他函数还应该使用noexcept关键字明确指示不使用异常来让编译器有优化空间。函数的错误返回应该定义Error类来实现。(2022-3-26,最近看到C++之父对C++异常的定义为错误码的衍生,他认为不应该完全使用异常来代替返回错误码,但异常也有它专门的用途,错误码和异常应该相辅相成,大多数情况下还是应该返回错误码,但是在某些条件下使用异常会有更好的效果。但是C++现在分为两大阵营,一类完全使用异常,另一类完全禁止异常,没有人或组织会同时使用异常和错误码,这也可以理解,如果同时使用可能并不是所有人能搞清楚什么时候该用异常,什么时候该返回错误码。这里采用返回错误码(QT里是定义Error类)是因为C++不像java的ide那样能够补全部分异常,如果一个函数会抛出异常的话外部可能根本不知道这个异常是什么类型,当然这也可能是我对异常的定义不太明确导致的。)
  2. 在框架或公共库中可以适当定义宏来使用,但是在业务代码中禁止定义复杂宏。因为框架为了保证通用性可能需要使用宏来减少客户代码量,但是业务代码通常功能明确,根本不需要使用宏(这里只是针对QT而言,如果原生C++,有些功能不用宏可能会写死人)。
  3. 属性只有private和public两种,类属性只能是private,子类需要使用父类的属性应该使用父类提供的getter,只要有功能函数则都应该定义为类。定义结构体只有两种情况,第一种是如第二条所示的类属性的定义方式;第二种是pod对象(只包含数据,不包含任何功能函数的的集合体),结构体的属性应该定义为public。
  4. 注释采用doxygen的格式,doxygen分java和qt风格,这里采用qt的风格。
/*!
  * \brief 
  * \param 
  * \return 
  */
  1. 文件命名采用java的风格。通常情况下一个文件内只定义一个类,所以文件名就是类名。但这并不绝对,有些额外的类可能和该类关联性较强或者只在该类中使用,那么也可以定义在同一个文件内(需要自行取舍),那么此时的文件名同样应该为向外开放的最主要的类名。
  2. cpp中的头文件引入顺序采用普遍使用的方式(按照库的稳定性排序):
#include "ObjectTest.h" // 本类对应头文件

#include <stdio.h> // C语言标准库头文件

#include <iostream> // C++标准库头文件

// 平台对应头文件 如windows.h

#include <QDebug> // QT库头文件
#include <QEvent>
#include <QThread>

// 其他第三方库头文件

#include "ThreadTest.h" // 本项目其他文件
  1. 只有接口提供者才能使用virtual,重写父类函数时不使用virtual,而是使用override
class I
{
public:
    virtual ~I() = default;
    virtual void a() = 0;
};
class C : public I
{
public:
    ~C() override {} //!< 使用override
    void a() override {} //!< 不使用virtual,而是用override
};
  1. 指针和引用的位置应当靠近变量一侧,比如const int *ptr = nullptr;这是个人审美习惯。
  2. 一行代码的字符不超过120(clang-format默认是80个,我觉得太短了)
  3. 其他的想到再慢慢补。

其他诸如入参的时候应该用const Type &的形式来提升效率的东西这里就不多说,这里只是规定编程风格相关的规范。
下面直接附上我个人使用的.clang-format文件。注意这个文件里面有些内容可能会变动,因为可能我并没有用到里面的全部格式,但常用的基本确定了

---
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: DontAlign
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
  AfterCaseLabel: false
  AfterClass: true
  AfterControlStatement: false
  AfterEnum: false
  AfterFunction: true
  AfterNamespace: false
  AfterObjCDeclaration: false
  AfterStruct: true
  AfterUnion: false
  AfterExternBlock: false
  BeforeCatch: false
  BeforeElse: false
  IndentBraces: false
  SplitEmptyFunction: true
  SplitEmptyRecord: true
  SplitEmptyNamespace: true
BreakAfterJavaFieldAnnotations: true
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
  - forever
  - foreach
  - Q_FOREACH
  - BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
  - Regex:           '^<Q.*'
    Priority:        200
    SortPriority:    200
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 4
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PPIndentWidth: 1
PenaltyBreakAssignment: 150
PenaltyBreakBeforeFirstCallParameter: 300
PenaltyBreakComment: 500
PenaltyBreakFirstLessLess: 400
PenaltyBreakString: 600
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 50
PenaltyReturnTypeOnItsOwnLine: 300
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
  - Q_UNUSED
  - QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Never
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值