C++编程风格

5

我是一名有用的助手,可以为您进行文本翻译。

现在我需要选择几个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
}

否则

否则 属于新行,见上一个例子。

if语句和大括号

即使是在 ifelse 后面只有一行代码,也应该用大括号括起来。

例如:

if (someInt > 100)
{
    someInt = 100;
}
else
{
    someInt /= 2;
}

方法调用

箭头和点周围不要留空格。

示例:

Object obj;
Object* oPtr = new Object();

obj.Method();
obj->Method();

头文件

  1. 使用#pragma once代替宏定义的保护。 (#pragma once在某些编译器中不是标准,因此必须使用宏定义的保护)
  2. 每个类只有一个头文件。
  3. 头文件仅用于定义,执行指令必须在相关的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

错误处理

如果函数可能会失败,它必须返回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;
};

格式化

  1. 对齐请使用4个空格或制表符。
  2. 长行折行,不要超过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;

这是我们决定使用的全部内容,问题是,我们是否漏掉了什么?还有,是否存在任何全球不可接受的问题?

如果有任何不清楚的地方,请随意评论并询问为什么选择某些内容。

希望对后来的读者有所帮助。


5
我还没读完全部内容,但我要指出,将变量首字母大写并不是标准做法。这样会让它们难以与类区分开来。通常的标准是小写字母开头,然后使用驼峰命名法。 - Dave
4
关于错误处理,如果您不反对使用异常(可以理解),请使用它们。没有必要使用特殊的错误参数和最后一个错误方法,因为使用catch就足够了。 - Dave
1
保持一致的编码风格是很好的。我对其他人唯一的指导是使用宏UPPERCASE_LETTERS并将其保留仅用于宏。 - user2249683
1
顺便提一下,如果您不确定,页面顶部有一个很好的帮助链接,其中列出了哪些问题类型应该避免提问?。其中明确指出:闲聊、开放式问题会降低我们网站的实用性,并将其他问题推到前页之外。如果您提问的动机是“我想参与关于______的讨论”,那么您就不应该在这里提问。 - chris
2
你有问题吗?就是以问号结尾的句子,而不是一篇论文。 - Jim Balter
显示剩余18条评论
2个回答

2

不确定这应该是一个答案还是一个评论。我将其发布为答案,以便其他人更容易对此进行评论。

我不太喜欢您提出的缩进命名空间的方式。一些项目的命名空间可以有相当深的嵌套级别,这真的会使代码难以阅读。


1
我通常只缩进我的 detail 命名空间,而且没有短行长度限制,只是根据我的屏幕宽度或者类似的方式。 - chris

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接