编码样式与风格(重要)

C++的编码风格非常灵活,几乎每一个熟练的C++程序员都有自己的偏爱与习惯。但是,无论是否以JUCE类库为主进行编码,都请遵循以下建议(这也是Jules所提倡的)。

总的原则:风格一旦确定,应严格遵循且始终如一,无论个人项目,还是团队合作。

基本布局和空格
 不要使用TAB制表符,代之以4个空格
 每个花括号独占一行。右花括号下面留一个空行
 二元运算符的前后使用空格,特别是赋值运算符“=”号前后必须使用空格
 逗号前面无空格,逗号后面加一个空格
 左圆括号之前使用空格。如果括号内无内容(比如无参函数),则可不使用空格。
 左圆括号之后不使用空格

笔者(Running)见过太多太多程序员,编码时几乎从来不留空格,特别是二元运算符左右两侧,逗号右侧,带参函数的参数列表左括号之前等等。甚至很多so-called资深专家或牛人大师也这么蛮干。实在令人唏嘘。这种人神共愤的恶习请务必及早矫正!想象一下用英文写作,如果单词和标点之间不留空格……#@¥%#@¥#¥@*&*……&% 不要忘记,用高级语言编程,本身就是一种正式的英文写作。

 if、for、while、switch等语句之前使用空行。执行后留一个空行。除非有多条短小的语句,为了排版和阅读清晰,可将它们逐行排列并垂直对齐
 if-else语句中,如果if中使用了花括号,那么else中也要使用花括号,反之亦然
 声明指针时,“*”号紧接在类型之后,而不是与类型分开,之后是空格和指针变量名称
 声明多个同类型的指针变量时,每个均分行声明,而不是在一行中声明
 引用型对象的声明同上。即:声明指针和引用时,“*”和“&”之前无空格,之后留一个空格
 声明常量时,const位于最前面,而不是位于数据类型和对象名之间

命名约定
 指针、变量、对象和函数名使用驼峰式风格,小写字母开头
 类、结构体和枚举类型同样使用驼峰式风格,但以大写字母开头。枚举常量小写字母开头
 所有名称应清晰直观,描述完整,不要使用代表数据类型或物理属性的简写前缀,绝对禁止整个名称就是简(缩)写,绝对禁止根本就毫无意义的字符数字
 所有标识符中避免使用下划线。特殊的宏定义和预编译指令除外
 宏和预编译指令全部用大写字母,单词之间可使用下划线。尽量避免使用宏定义,除非万不得已
 只要有可能,声明对象和函数时应尽可能的使用const加以限制
 如果该函数不抛出异常,则原型声明的最后使用“noexcept”关键字
 如返回一个临时对象,比如String或指针,则返回值应始终为const
 函数中声明变量应使它们的作用域最小化,马上要用到时才声明,而不是声明在函数的开始处
 函数形参应尽可能地使用const引用,尽量不使用指针
 检测指针是否有效,不要使用“if (myPointer)”这样的语句,这牵扯到隐式类型转换。应明确告知编译器,正确的写法是:“if (myPointer != nullptr)”。if表达式更好的写法是将常量放在关系运算符的左侧:if (nullptr == myPointer)
 关于类型强转:C++内置的基本数据类型,可使用C风格转换语句:(float) doubleValue; 类类型一律使用static_cast 或dynamic_cast 强转运算符。如果强转时需借助最底层的位模式,则显式使用reinterpret_cast
 在编译器尚未广泛支持C++ 11标准之前,如需64位整型变量,一律使用int64或uint64,而不是int或unsigned int

类和对象
 尽可能不用或少用“delete”, “deleteAndZero()”等运算符和函数,尽量使用ScopedPointer、OwnedArray、ReferenceCountedObject(引用计数)等可以自动管理生命期的对象
 除非无可选择,否则尽量避免使用new运算符。每次要敲new的时候,应仔细考虑是否还有其他更好的解决方案。本地变量或对象优先使用栈内存分配,而不是堆内存分配
 绝对禁止使用new或malloc来声明数组,应使用HeapBlock类来完成此事
 尽量避免使用static变量和全局变量
 数组初始化为零,优先使用”= { 0 };” 如果情况不允许,则使用zerostruct()或zeromem(),而不是memset()
 谨慎使用Component::deleteAllChildren(),如果有更好的方案,应避免使用该函数
 首先声明类的public区。通常,构造和析构函数位于最前面。而后是protected和private区
 多重继承的类,第一个基类与类名在同一行,其他基类分行排列,垂直对齐。
 private区中首先是基本类型的变量,而后是JUCE类的对象,接着是自定义类的对象,最后是private成员函数
 如果某个类无需拷构与赋值函数,则使用JUCE_DECLARE_NON_COPYABLE(类名)宏,置于private区的最后
 如果某个类无需拷构和赋值运算符重载,并且有可能创建堆对象,则使用该宏:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (类名)。
 如果某个类需要拷构函数,同时有可能创建堆对象,则使用:JUCE_LEAK_DETECTOR(类名)。这种情况下,要确保拷构函数中没有使用new运算符
 空指针绝对禁止使用“NULL”、“null”或“0”,而是使用C++ 11标准中明确规定的“nullptr”。
 自定义类时,优先使用聚合与组合,而非继承。

其他
 创建对象时,不要使用赋值运算符(即对象间的赋值),比如:const String s = “foo”; 而是使用更加规范和高效的构造函数式:const String s (“foo”);
 坚决避免类似这样的垃圾语句:const String s = String (“123”);
 少用宏定义,用const和inline函数替代之。万不得已使用,要及时#undef取消之
 使用前自增和前自减(++X和–X),特别是循环语句中:for (int = 10; –i >= 0; )
 使用Doxygen所支持的注释格式,每个类及其public成员函数必须要有注释,第一行简述功能,第二行为空行,后续行给出详细的说明或用法。如有必要,给出解决思路,算法公式,参考文献,网址,伪代码并附带示例(@code … @endcode),若涉及到其它类,则使用“参见类/函数”(@see XXX)。
 每次修改代码之前,先改注释。如果当天不能完工,注释最后添加“[hasn’t been done yet]”等标志。完工后及时删除。如有必要,注明每次修改的日期及原因。团队协作,还需注明修改者姓名或昵称。如使用Git,则后两点不必多此一举。
 尽量使用语法正规、用词精确、句式简洁的英文注释。如英文实在太差,可酌情以汉语拼音替代之。关于汉语拼音的写法,要做专门的约定与统一。
 函数体内避免使用“//=======”分割型注释,头文件的类定义中,根据需要或功能,酌情使用分割型注释,源文件的类实现中,每个函数之间使用分割型注释(非常短小的函数之间可不用)。函数内部的关键语句必须给出注释。