不确定我的问题是否适合 StackOverflow 问题的所有规则,但我认为这对未来的用户会有帮助。
现在我需要为我参与的几个 C++ 项目选择编码风格。这些项目足够大,每个项目都会有几个程序员在工作。所以我们需要均衡我们的代码风格。此外,我们想选择社会可接受的编码风格,所以首先我会告诉我们已经决定要拥有什么。我的问题是,如果我们的某些选择不是为社会所接受的,以及其他通常使用 C++ 编码风格规则的选择是什么。
所以在这里我们选择了:
文件命名
以大写字母开头,每个新单词都有一个大写字母(没有下划线,没有空格)。
例如:
VeryImportantClass.h
VeryImportantClass.cpp
命名空间命名
以大写字母开头,每个新单词都有一个大写字母(没有下划线,没有空格)。对齐也应该是适当的。
例如:
namespace Drinks
{
namespace AlcoholDrinks
{
}
}
命名空间结构
头文件中只有函数/方法原型,在cpp
文件中实现,避免using namespace
用于实现文件。
例子:
//header
namespace CommonStuff
{
namespace SystemParameters
{
bool IfWindows();
//some more stuff...
}
}
//cpp file
namespace CommonStuff
{
namespace SystemParameters
{
bool IfWindows()
{
//some stuff...
return ...;
}
}
}
类和结构命名
以大写字母开头,每个新单词都有一个大写字母(没有下划线,没有空格)。没有C类前缀或S类前缀。我们决定 - 它只是更多的打字。
例子:
class MyClass
{
};
struct MyStruct
{
};
类或结构
在某些情况下,我们很难理解我们是否需要类或结构。如果结构只保留一些分组数据 - 它是struct
. 如果结构保留数据并具有方法 - 它就是class
. 特殊方法是构造函数、析构函数和比较运算符。
例子:
class MyClass
{
public:
MyClass();
~MyClass();
void SetValue(int value);
int GetValue();
void PrintValue();
private:
int m_value;
};
struct MyStruct
{
MyStruct();
~MyStruct();
int value;
};
类型名称
以大写字母开头,每个新词都有一个大写字母(没有下划线)。
例如:
typedef std::string String;
typedef std::vector<String> StringVector;
变量类型
使用我们自己的预定义类型,我们有:
typedef std::string String;
typedef std::vector<String> StringVector;
typedef unsigned char Byte;
typedef std::vector<Byte> ByteVector;
//etc.
变量命名
以一个小写字母开头,每个新词都有一个大写字母(没有下划线)。
例子:
String messageLicenseExpired = "Your product version is expired, please...";
int importantNumber = 13;
类变量命名
以前缀m_开头,然后单词以小写字母开头,每个新单词都有一个大写字母(没有下划线)。
例子:
int m_myVariable;
int m_otherVariable;
常数
使用所有大写字母和下划线。
例子:
const String PRODUCT_NAME = "our product";
const Byte IMPORTANT_NUMBER = 13;
常量或预处理器
如果值将被检查使用#ifdef
或其他一些,那么它必须是预处理器定义。否则就是const
。
例如:
#define FAILURE_FACTOR_FOR_DEBUG 50
const int MAGIC_NUMBER = 5;
//some code...
String newString = someString.substr(MAGIC_NUMBER);
//some code...
//not the best example, but I think it is understandable.
#ifdef _DEBUG
int someValue = FAILURE_FACTOR_FOR_DEBUG;
#else
int someValue = 0;
#end
函数和方法命名
以大写字母开头,每个新词都有一个大写字母(没有下划线)。
例如:
int CalculateSometing (int n);
void ToUpper (String& someStr);
大括号
大括号应始终进入新行,初始化除外。
例子:
int arr[] = {1, 2, 3};
if (arr[0] > 10)
{
//do something
}
else
{
//do something else
}
别的
else
属于新行,见前面的例子。
if 语句和大括号
if
在 or 之后甚至else
应该包含单个代码行。
例子:
if (someInt > 100)
{
someInt = 100;
}
else
{
someInt /= 2;
}
方法调用
箭头和点周围没有空格。
例子:
Object obj;
Object* oPtr = new Object();
obj.Method();
obj->Method();
头文件
- 使用
#pragma once
而不是定义守卫。(#pragma once
不是标准的,因此在某些编译器中必须定义警卫) - 一个标题只适用于一个类。
- 头文件仅用于定义。执行指令必须在相关
cpp
文件中,即使它是 getter 或 setter。这是因为头文件的更改会导致长时间编译。
指针和引用
如果可能,请使用引用而不是指针。如果可能将参数作为引用传递(对于对象),const
如果值不会更改,则更喜欢作为引用传递。
例子:
String ToUpper(String str); //bad
String ToUpper(String& str); //better
String ToUpper(const String& str); //best
void ToUpper(String& str); //also solution
错误处理
如果函数可能失败,它必须返回成功和失败的bool
值。对于类方法是必须的。对于可能失败的函数,应该通过附加参数返回错误代码,例如我们也决定不在我们的代码中使用异常。true
false
GetLastError()
bool Function(int param, int* errorCode = NULL)
类结构
在头文件中首先是公共方法(构造函数和析构函数在它们的顶部),受保护的方法,受保护的变量,私有方法,私有变量。没有公共变量,使用 getter 和 setter。
例子:
class MyClass
{
public:
MyClass();
~MyClass();
int GetPrivateValue();
void SetPrivateValue(int value);
int GetProtectedValue();
void SetProtectedValue(int value);
protected:
void SomeMethod();
int m_protectedValue;
private:
void SomePrivateMethod();
int m_privateValue;
};
格式化
- 对齐使用 4 个空格或制表符。
- 长换行,不再是 120 个符号的行。
自记录代码
评论总是受欢迎的,但最好的选择是给变量和函数命名来解释一切。
例子:
void Function (const String& str, const String& str2, StringVector& vect); //very bad
//This functions tokenize string, str is input string, str2 is delimiters string, vect output
void Function (const String& str, const String& str2, StringVector& vect); //quite bad
void Tokenize (const String& inputString, const String& delimiters, StringVector& output); //good, anyway comments using this declaration also welcome.
& 和 * 位置
写在变量类型之后&
。*
例子:
String* strPtr;
String& strRef;
这是我们决定使用的全部,问题是,我们没有错过什么吗?另外,有什么全球不能接受的吗?
随意评论并询问是否有不清楚的地方,为什么我们选择了一些。
希望对后来的读者有所帮助。