Ronimo编程风格指南(的我的修改版)

原Ronimo编程风格指南的译文在 http://gad.qq.com/program/translateview/7213889

译者: 刘超(君临天下)

 

这里根据情况进行了修改

Ronimo(修改版)编程风格指南

      每一个规则都有例外。但是,尽可能的对于所有的代码保持固定的布局和风格。绝大多数是很难接受的,固定的编程风格需要一个人舍弃自己的风格来遵守这些规则。一旦习惯了这些规则,那么将会很容易的阅读类似的代码。

      当使用其它编程语言而不是C++进行编程时,尽量保持与C++编程标准的一致性,但是当然也包括一些原因。在底层也会有一些关于C#的特殊的声明。

C++

l  所有的代码和注释应该是英式英文。而不是美式英文。因此,以下这些是正确的: colour, centre, initialiser。而这些是不正确的:color,center, initializer.

l  每一个逗号之后应该有一个空格,例如 doStuff(5, 7, 8)

l  每一个操作符前后应该有空格,例如:使用5 + 7来替代5+7,仅当有一部分总是成出现,比如a+b + Var + c*d

l  Tabs按键应该有相同的四个空格的大小。应该将Tabs作为制表符,而不是空格。

l  函数和静态变量在.h文件和.cpp文件中应该具有相同的顺序。

l  使用#pragma once代替旧的文件防护(我们最近才开始使用这个,因此你仍然能在我们的代码中看到大量的旧的文件防护)。

l  尽量让函数长度短,每个函数最好不要超过50行。

l  避免使用非常大的类。尽可能的将一个类进行分割为你能够清晰的进行分割的样子。通常,尽可能的让一个类保持在750行以下。但是如果分割会造成代码的混乱,那么不要对类进行分割。以下是一些混乱的例子:过渡耦合的类,友元类和复杂继承类。

l  不要写太长的超过普通屏幕1920*1080分辨率的代码(确保资源管理器能够很好的出现在屏幕上),代码主要部分在120字符以内,个别少量难以切割的行可以达到150字符,没必要死守80字符规则

l  当将一条较长的语句分割为多条语句时,确保相关括号的缩进是正确的。例如:

1

2

3

myReallyLongFunctionName(Vector2(bananaXPos + xOffset,

                 bananaYPos * multiplier),

                 explodingKiwi);

l  尽可能的在使用之前进行声明:尽可能在头文件中使用较少的include语句。例如,在使用Bert类时,将#include“Bert.h”语句移动到cpp文件中。

l  include语句和声明的顺序如下:?????

n  在我们代码的最开始使用进行声明(按照字母表顺序)

n  然后开始include语句(按照字母表顺序)

n  空一行

n  然后对于每一个库:

u  对用到的库进行声明(按照字母表顺序)

u  库对应的include语句(按照字母表顺序)

l  与cpp文件对应的h文件应该被包含在最顶端

l  不要在函数中定义静态变量。而是使用类成员变量进行代替(尽可能使用静态的)。????

l  正确的使用const。

l  变量和函数的命名应该具有可读性。长一些的命名是没有问题的,而不可读的命名是不行的。只有在命名是十分清晰而且被大众所知(行业范围)的情况下或者是局部没有合适名字的临时变量才可以使用缩写,以新员工通过网络搜索引擎能快速理解为标准对于公司级别的单词组尽量不缩写,缩写必须在所在文件有精确定义。

l  类、结构体和枚举类型的首字母应该大写。每一个单词首字母大写。在变量名中不要使用下划线。公开函数使用大写字母开头,私有或面向对类特别熟悉的特别函数小写开头例如:

1

2

3

4

5

class MyClass

{

public:

  void PublicFunction();

  void doSomeThingSpecial();

private:

  void someFunction();

  int someVariable;

};

l  成员变量不要使用m_在变量之前加m或者_进行命名。函数应该尽可能的短来确保在类中的声明。不要使用this->来标记成员变量。

l  超过三行的函数的实现永远不要写在头文件中,或者将他们实现在头文件尾部

l  模板函数不要在cpp文件中实现,而是要在主头文件包含的另外一个头文件中实现。这样一个类会包含3个文件:MyClass.h, MyClassImplementation.h和MyClass.cpp。例如:

1

2

3

4

5

6

7

8

class MyClass

{

  template <typename T>

  void doStuff(T thingy);

};

 

 

#include "MyClassImplementation.h"

l  模板类型使用T。如果有别的相关的信息,你可以在T后面增加单词,例如TString。

l  几个类永远不要定义在同一个头文件中,除非一个类是另外一个类的一部分或者当前头文件的辅助

l  在函数之间要有两个空白行(在cpp文件中)。

l  使用空白行对代码进行结构化和组合使得代码具有可读性。对大函数中多个阶段用{}组织。

l  为代码添加大量的注释。

l  在每一个类之前写一段短的解释来说明该类是用来干什么的。尤其确保解释他们之间的关系(例如:该类是用来帮助类X做Y的)。

l  分支之间的{和}独自占据一行,不要将它们和if或者是for放在同一行。当然也不要漏掉。特殊情况是如果在if声明之后存在大量的相似的语句,在这种情况下,把它们放在同一行是允许的。例如:

1

2

3

4

if         ( banana &&  kiwi && length > 5) return cow;

else if ( banana && !kiwi && length > 9) return pig;

else if (!banana && !kiwi && length < 7) return duck;

else                                                         return dragon;

l  当写do-while函数时,将while与}放在同一行。

1

2

3

4

Do

{

  blabla;

} while (bleble);

l  switch语句的缩进如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

switch (giraffeCount)

{

  case 1: text = "one giraffe";  break;

  case 2: text = "two giraffes"; break;

  case 3:

  // If it's more than one line of code

    doStuffOnSeveralLines;

    text = "three giraffes";

    break;

  case 4:

  {

    // Can add curly braces for readability

    int x = getComplexThing();

    text = "quadruple giraffe";

    break;

  }

}

l  h文件和cpp文件中的函数参数应该具有相同的命名。

l  如果一个函数参数和类成员变量有着相同的命名,那么重新换一个命名,或者在函数参数之后增加一个_。例如:

1

2

3

4

void setHealth(float health_)

{

  health = health_;

}

l  预编译指令(以#开始的语句)应该尽可能的少,除了#include和#pragma once。

l  不要写宏来完成常规业务

l  函数内部变量只有在需要的时候进行声明,不要将它们全部放在函数开始。声明同时立刻用={}或={xxx}赋值,除非是足够大的数组用={}赋值会造成性能问题。

l  大部分结构体成员变量应在声明同时在结构体内部给予默认值,在构造函数的初始化列表如果对其初始化,那么会无视结构体处的默认值。在构造函数中,尽可能的使用初始化列表,而不是在结构体内部进行变量初始化。初始化列表的每一个变量独自占据一行。尽量让保证初始化列表中变量的顺序与类头文件中变量的顺序是一致的,除非这个初始化时有变量依赖顺序

l  不要使用异常处理(除非你用到的第三方库需要它),吝啬地使用throw

l  不要使用RTTI(因此也不要使用动态转换)。RTTI会一定程度的影响性能,但是更重要的是RTTI常常违背面向对象设计原则。

l  只有在十分需要的情况下使用reinterpret_cast和const_cast。

l  不要提交编译时包含错误和警告的代码(也不要禁用警告/错误)。

l  不要提交违背现有功能性的代码。

l  不要全局变量。使用静态成员变量来代替。????

l  使用我们自己的MathTools::abs来代替std::abs。这是由于std::abs在不同平台的实现是不一致的,这样会造成难以发现的bug。

l  总是显式的使用命名空间。不要在代码中使用 using namespace std 这种语句。

l  永远也不要使用go-to语句,除非你能保证自己和别人在现在和未来都不会使用goto穿越某些变量的生存周期如果你使用了,我们会检测出来的。

l  不要使用逗号操作符,例如 if(I += 7, I < 10)

l  不要使用联合体。

l  不要使用函数指针,除非一些库(例如STL排序函数)需要它。除非你有能力编写基础库。用lambda代替std::bind和成员函数指针。

l  只有在非常简单的情况下才能应当使用三元运算。永远不要嵌套使用三元运算。可以使用的一个例子如下所示:

1

print(I > 5 ? “big” : “small”);

l  对于艺术家或者是设计者,在进行计数时从0开始,正如代码中的数组一样。一些旧的工具可能仍然使用从1开始计数,但是任何新的艺术家的开发要从0开始。

l  当确认指针是否为空时,确保使用显示的方法。因此,使用 if(myPointer != nullptr) 来代替 if(myPointer),if(myPointer==nullptr)代替if(myPointer)

l  尽可能的使用资源获取即初始化(RAII)。不要创建一个独立的初始化函数 initialise(), 而是在它的构造函数里进行完整的初始化,这样将不会出现一个不完整的状态。除非这个类无法避免不完整的状态。

l  把构造函数和析构函数写在一起:为每一个new及时的写上对应的delete,这样你就不会在后面忘记写了。

l  如果你添加了临时的调试代码,那么使用QQQ进行注释。永远不要将有QQQ的代码进行提交:在提交代码之前将调试的内容进行删除。只有长期的调试代码才允许提交,需要对非必要的代码进行注释。

l  如果你想要为之后做的事情进行标记,那么请使用QQToDo #ToDo。如果这些事情是后续你自己完成的,那么在之后添加你的名字,例如QQToDoJ #ToDo yourName。只有在这件事情真的无法完成的时候,才可以将QQToDo #ToDo yourName进行提交。使用#ToDo的好处是VisualAssistX能够识别并整理他们。

l  在每一个类中先定义函数,再定义变量。关键词顺序是public/protected/private。这意味着在一个头文件中你不得不多次使用关键词public/protected/private(首先用于定义函数,然后用于定义变量)。

l  对于每一个类,先定义构造函数,接下来紧跟析构函数。如果它们是private或者protected类型,同样将它们放在类的最开始。

l  当一个变量有两种选择时,但是很清晰的并非是true/false,那么考虑使用枚举变量来代替布尔变量。例如,对于direction不要使用布尔类型isRight。取而代之的是使用包含Left和Right的枚举类型Direction。

l  不要使用std::stringstd::stringstream,使用我们自己的类RString,RStringstream,WString和WStringstream(这些类有着我们的内存管理机制),因为我们通常已经实现了他的替代品

l   浮点数变量time总是表示上一帧的时间,以秒为单位。如果time表示其它内容,请显示声明,例如使用timeExisting进行命名。

l  确保所有的代码与帧率都是无关的,这样使用浮点数变量time总是能够获取时间

l  对于预期的结构进行显示清晰的定义。例如,避免使用下述定义:

1

2

3

4

5

if (yellow)

{

  return banana;

}

return kiwi;

哪一个是真正预期的结果,它们和yellow有什么关系,banana和kiwi都可能是返回结果。使得该代码更容易阅读的显示的定义如下所示:

1

2

3

4

5

6

7

8

if (yellow)

{

  return banana;

}

else

{

  return kiwi;

}

l  使用nullptr替代NULL。

l  我们仅对复杂的迭代类型使用auto。对于其它变量,我们使用显式的类型进行定义。

l  尽可能使用基于范围的循环,例如:

1

for (const Banana& ultimateFruit : myList)

(注意当没有使用指针时,引用类型的定义是很重要的,在这个例子中,如果使用其它定义方式,那么Banana将会被复制一份。)

l  尽可能的使用override和final关键词。

l  如果一个函数是虚函数,总是要在函数之前添加关键词virtual,不仅仅在父类中添加该关键词,在它的每一个实现的子类中同样也要添加。

l  使用强制的类型定义枚举类型,因此使用class关键词进行定义。这样它们的转换和类一样。例如:

1

2

3

4

5

6

enum class Fruit

{

  Banana,

  Kiwi,

  ApplePie

};

l  不要使用右值引用,除非你真的非常需要它们。

l  尽可能的使用unique_ptr。如果一个对象不是其所有的,那么将它存储为一个普通指针。

l  避免在初始化列表中创建复杂类型的实例。简单的复制和设置操作在初始化列表中完成,但是更加复杂的代码像是调用new操作,应该在构造函数内部完成。下面是上述操作的一个例子:

1

2

3

4

5

FruitManager::FruitManager(Kiwi* notMyFruit):

  notMyFruit(notMyFruit)

{

  bestFruitOwnedHere.reset(new Banana());

}

l  只有当真正存在共享关系的情况下才可以使用shared_ptr。在通常情况下,尽量避免共享关系并使用unique_ptr。避免滥用shared_ptr尤其是目标可能携带其他shared_ptr甚至导致循环引用的情况。

l  充分利用std中的算法如sort、find_if等,这有助于直接表达算法意图,降低阅读代码的难度。避免使用for_each。

l  对于单行过长的代码可以写成如下形式:

1

2

3

4

5

6

auto it = std::find_if(myVec.begin(),

            myVec.end(),

            [id = 42] (const Element& e)

            {

                return e.id() == id;

            });

l  不要使用MyConstructor= delete(这在我们可能用到的一些编译器上不支持)。

l  不要在初始化列表中使用C++11的特性(这在我们可能用到的一些编译器上不支持)。因此,我们不使用如下形式:

std::vector<int>thingy = {1, 2, 3};

l  不要使用任何C++14所增加的特性。

C#

l  将变量定义在文件的开头而并非末尾。在函数和变量之间进行一个严格的区分(就像我们在C++中做的一样),因此,首先定义所有变量,然后定义所有函数。

l  所有异步函数必须以Async作为名称的结尾,例如:eatBananaAsync。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值