規範的代碼可以促進團隊合作,規範的代碼有助於提升代碼的可讀性,註釋規範自動生成文檔。
1.頭文件規則
通常每一個.cpp 文件對應一個.h 文件,當然也有特列,main 函數入口 cpp 文件沒有對應的.h, 只有純虛函數的接口類只有.h 文件沒有.cpp。
1.1.#define 防止多重包含
所有頭文件都應該使用#define 防止頭文件被多重包含,這個多重包含指的是一個 cpp 編譯過程中不被多次包含,如果有多個 cpp 都調用,那這個文件還是會被包含多次,所有頭文件中不要做定義。
命名格式如果是普通的業務邏輯類的代碼比如 x_msg_task.h 的文件就直接定義 X_MSG_TASK_H,如果是做類庫或者公用的庫,把項目名稱加在前面。
實例在 x_msg_task.h 頭文件中:
#ifndef X_MSG_TASK_H
#define X_MSG_TASK_H
//你的聲明代碼
#endif
1.2.減少頭文件依賴
使用前置聲明(forward declarations)儘量減少.h 文件中#include的數量。
當一個頭文件被包含的同時也引入了一項新的依賴(dependency),只要該頭文件被修改 , 代碼就要重新編譯。如果你的頭文件包含了其他頭文件,這些頭文件的任何改變也將導致那些包含了你的頭文件的代碼重新編譯。因此,我們寧可儘量少包含頭文件,尤其是那些包含在其他頭文件中的。
比如用到XThread 類的指針,在頭文件中可以不#include 類文件,而是直接用 class XThread;的聲明,但如果類中定義的是實體對象,那就必須要引入頭文件。
在.h 中儘量不引用頭文件,在.cpp 中引用。
1.3.頭文件中不導入命名空間
頭文件中不調用 using 導入命名空間, 調用是直接寫命名空間比如std::string str;
命名空間導入在.cpp 中做,因爲你沒法確認你的.h 會被什麼樣的文件調用, 會不會參數命名衝突。
test_head1.h
/*
解決頭文件在一個cpp中多次引用
*/
#ifndef TEST_HEAD1_H
#define TEST_HEAD1_H
//頭文件中儘量不要using 命名空間,減少協作問題
#include <string>
class TestHead1
{
public:
TestHead1();
protected:
int x2;
std::string str;
};
#endif
test_head2.h
//#include "test_head1.h"
//前置聲明,減少頭文件依賴
class TestHead1;
class TestHead2
{
public:
TestHead2();
protected:
TestHead1 *head1 = 0;
};
test_head1.cpp
#include "test_head1.h"
using namespace std;
TestHead1::TestHead1()
{
}
test_head2.cpp
#include "test_head2.h"
TestHead2::TestHead2()
{
}
main.cpp
#include <iostream>
using namespace std;
#include "test_head1.h"
#include "test_head2.h"
int main()
{
cout << "test cpp" << endl;
return 0;
}
2.類規則
2.1.構造函數(Constructor)的職責
構造函數中只進行那些沒有實際意義的初始化就是非業務邏輯的初始化,儘量在 Init()方法集中初始化業務邏輯數據。
2.2.結構體和類(Structs vs. Classes)
僅當只有數據時使用 struct,其它一概使用 class。類和結構體的成員變量使用不同的命名規則。
2.3.繼承(Inheritance)
優先使用組合,如果必須使用繼承的話,只使用 public 繼承。
2.4.多重繼承(Multiple Inheritance)
儘量不用,如果必須要用,多重繼承中只有一個基類是有實現的,其他的都只能是接口類,不然內部對象空間分配容易產生問題。
2.5.接口(Interface)
接口是指滿足特定條件的類,這些類以 I 開頭(非必需)。只有純虛函數("=0")和靜態函數;
2.6.聲明次序(Declaration Order)
在類中使用聲明次序如下:public:、protected:、private:
每一塊中,聲明次序一般如下:
構造函數; 析構函數;
成員函數,含靜態成員函數; 數據成員,含靜態數據成員。
test_head1.h
/*
解決頭文件在一個cpp中多次引用
*/
#ifndef TEST_HEAD1_H
#define TEST_HEAD1_H
//頭文件中儘量不要using 命名空間,減少協作問題
#include <string>
#include "i_thread.h"
//聲明次序
//構造函數;
//析構函數;
//成員函數,含靜態成員函數;
//數據成員,含靜態數據成員。
//結構體當中不包含方法,如果要用方法換class
struct XData
{
int x = 0;
int y = 0;
};
class TestHead1:public IThread
{
public:
//1 構造函數
TestHead1();
//2 析構函數
virtual ~TestHead1() {}
//3 成員函數
bool Init();
//重載純虛函數
virtual void Exec();
//4 數據成員
int index = 0;
protected:
int x2;
private:
std::string str;
};
#endif
test_head1.cpp
#include "test_head1.h"
using namespace std;
TestHead1::TestHead1()
{
//不做實際意義的初始化,業務邏輯無關
//業務邏輯初始化Init
}
//重載純虛函數
void TestHead1::Exec()
{
}
bool TestHead1::Init()
{
//業務邏輯初始化
return true;
}
test_head2.h
//#include "test_head1.h"
//前置聲明,減少頭文件依賴
class TestHead1;
class TestHead2
//如果用繼承用public繼承
//class TestHead2:public TestHead1
{
public:
TestHead2();
protected:
//儘量不用繼承,用組合
TestHead1 *head1 = 0;
};
test_head2.cpp
#include "test_head2.h"
TestHead2::TestHead2()
{
}
3.格式規則
3.1.空格還是製表位(Spaces vs. Tabs)
只使用空格,每次縮進 4 個空格
3.2.括號格式
左右括號都單獨起一行
if (true)
{
//
}
4.命名約定
4.1.通用命名規則(General Naming Rules)
函數命名、變量命名、文件命名應具有描述性,不要過度縮寫,類型和變量應該是名詞,函數名可以用“命令性”動詞。
4.2.文件命名(File Names)
文件名要全部小寫,可以包含下劃線(_) my_useful.cpp。
4.3.Class 類型命名(Type Names)
類型命名每個單詞以大寫字母開頭,不包含下劃線:MyExcitingClass、MyExcitingEnum。 所有類型命名——類、結構體、類型定義(typedef)、枚舉——使用相同約定
4.4.變量命名(Variable Names)
變量名一律小寫,單詞間以下劃線相連,類的成員變量以下劃線結尾,如my_exciting_local_variable、my_exciting_member_variable_。
4.5.函數命名(Function Names)
普通函數:
函數名以大寫字母開頭,每個單詞首字母大寫,沒有下劃線: AddTableEntry()
成員存取函數:
class MyClass { public:
...
int num_entries() const { return num_entries_; }
void set_num_entries(int num_entries) { num_entries_ = num_entries; } private:
int num_entries_;
};
4.6.宏、枚舉命名
使用全部大寫+下劃線
枚舉名稱屬於類型,因此大小寫混合:UrlTableErrors。
enum UrlTableErrors
{
OK = 0, ERROR_OUT_OF_MEMORY,ERROR_MALFORMED_INPUT,
};
#define PI_ROUNDED 3.0
5.Doxygen 註釋規則
5.1.文件註釋
文件註釋通常放在整個文件開頭。項目註釋
///////////////////////////////////////////////////////////////////////////
/// @mainpage 項目註釋
/// @author 作者
/// @version 版本
/// @date 2019 年 07 月 10 日
///////////////////////////////////////////////////////////////////////////
文件註釋
///////////////////////////////////////////////////////////////////////////
/// @file 文件名
/// @brief 簡介
/// @details 細節
///////////////////////////////////////////////////////////////////////////
5.2.類定義註釋
///////////////////////////////////////////////////////////////////////////
/// @brief 類的簡單概述
/// @details 類的詳細概述
///////////////////////////////////////////////////////////////////////////
5.3.常量/變量的註釋
/// 代碼前註釋
常量/變量
常量/變量 ///< 代碼後註釋,一般是變量數量較多,並且名字短
5.4.函數註釋
///////////////////////////////////////////////////////////////////////////
/// @brief 函數簡介
///
/// @param 形參 參數說明
/// @param 形參 參數說明
/// @return 返回說明
///////////////////////////////////////////////////////////////////////////
xvideo.h
////////////////////////////////////////////////////
/// 項目說明
/// @mainpage 基於微服務架構的安全雲盤項目
/// @author Clement
/// @version 0.1.0
/// @date 2019年7月10日
////////////////////////////////////////////////////
////////////////////////////////////////////////////
/// @file xvideo.h
/// @brief 視頻處理類文件(文件說明)
/// @details 視頻處理類文件
////////////////////////////////////////////////////
#ifndef XVIDEO_H
#define XVIDEO_H
////////////////////////////////////////////////////
/// @brief 視頻處理類(類說明)
/// @details 視頻處理類用於生成視頻的截圖\n
/// 說明換行
////////////////////////////////////////////////////
#include <string>
class XVideo
{
public:
XVideo();
~XVideo();
////////////////////////////////////////////////////
/// 視頻截圖
/// @param path 輸入視頻文件路徑
/// @param out 輸出圖片路徑
/// @param sec 第幾秒截圖
/// @param width 輸出圖片寬度
/// @param height 輸出圖片高度
/// @return 返回截圖是否成功
bool Screenshot(std::string path,std::string out,int sec,int width,int height)
{
return true;
}
/// 對象索引
int index = 0;
private:
char buf[1024] = { 0 };///文件名緩存
};
#endif
xvideo.cpp
#include "xvideo.h"
XVideo::XVideo()
{
}
XVideo::~XVideo()
{
}
5.5.Doxygen 設置使用
設定項目名稱和項目語言
設定編碼方式(INPUT_ENCODEING)vs 的項目一般設置爲 GBK