C++ 编码规范

C++编码规范

游戏服务端

目录

C++编码规范

一、通用命名

二、格式

三、类.

四、作用域

五、C++特性

六、协议

七、注释

八、其它

一、通用命名

1.1   简写规则:常用单词缩写简写,如dns、id等,否则最好采用单词全称书写

1.2   局部变量:使用“_”连接,所有单词小写,如user_id

1.3   函数名:首字母小写,其余单词首字母大写,如addTask()

1.4   文件名:全部字母小写,单词中间采用“_”连接,如果内部定义类,请与类名一致

1.5   类名:全部单词均使用首字母大写,如SceneTemplate,对应的文件名为scene_template.h

1.6   宏定义:所有字母大写,单词中间采用“_”连接

1.7   枚举:所有字母大写,如果放于某个类内,第一个单词最好使用类名缩写,如定义了class SceneTemplate {

Enum {

       ST_XXX_XXX = 0,

       ST_XXX_CCC = 1,

}

}

二、格式

2.1   代码文件内不允许存在tab键,均采用4个空格代替,每次缩进4字节

2.2   每行代码不宜太长,100字符以内(21.5寸显示器屏幕对半分宽度),如果有换行情况,注意美观对齐,如方法名参数对齐,for循环内部变量对齐等

2.3   中括号使用,第一个{均在前一行末尾,如

if (xxx) {

     ……

} else {

     ……

}

PS:即使if内部只有一行代码,也需要用{}括起来不允许写成“if () xxx;”且,”} else {”必须在同一行

void func() {

     ……

}

2.4   每一行末尾不要存在空格符号,且每一空行不要存在空格符,vim可以使用set list查看

2.5   命名空间内的代码不要缩进,且内嵌的命名空间也无需缩进,如

namespace Foo{

namespace Bar{

void func() {

     ……

}

class {

     …

};

}

}

三、类

3.1   头文件

a)   头文件定义均采用预处理宏模式,防止重复包含头文件出现重定义错误

#ifndef XXX_H__

#define XXX_H__

……

#endif

其中XXX_H__均使用 命名空间_文件名_H__,文件名单词之间均使用“_”连接

b   成员变量

i) 均以m_开头,如m_id

ii) 包含多个英文单词组合而成是第二个单词首字母大写规则,如m_userId

c)   所有的类均在某一命名空间内,不允许单独存在

d)   根据实际需求使用public/protected/private,也是按照这顺序声明,尽量不要把成员变量暴露出来

e)   某些简单的func可在头文件直接实现,如:

void vip(int vip) { m_vip = vip; }

int vip() { return m_vip; }

PS:注意中括号两边均有空格

f)   如需引入其它类采用前置声明,不引入头文件,在cpp文件引入

g)   方法根据实际需求定义的时候需要归类

3.2   cpp文件

a)   方法均在命名空间内实现

b)   引入头文件顺序

i)当前类的头文件

ii)系统库

iii)自定义头文件(均按26个字母顺序编写)

PS:此3项中间采用空行分割

3.3   构造函数不要有比较复杂的数据初始化,及虚函数调用,如有需求使用init()方法封装,对象创建后调用初始化

3.4   当成员仅有数据时使用struct,无需使用class

3.5   面向对象三要素:封装,继承,多态。继承能减少代码的耦合度,根据适当的场景使用,以高内聚低耦合为准则,不要出现过度封装的情况

四、作用域 namespace

4.1  代码无需缩进

4.2  类需前置声明

4.3  除#include及引入非此作用域空间声明外,其余所有的代码均在namespace范围内

五、C++特性

5.1)   ++与--操作,如果不考虑返回值均使用前置,效率较高,减少一次数据拷贝过程,尤其是在迭代器里面操作时

5.2)   多线程并发下,对容器的读写赋值操作必须加锁,同时一个类里面只需声明一个锁即可,无需根据对象区分,多个锁情况下使用错误会发生死锁情况

5.3)   局部变量声明需要初始化,如果不初始化部分平台编译器可能给的默认值不一样,如int tmp;不同编译器tmp可能为0,也可能为随机值,int类型在声明为全局变量的时候默认值为0

5.4)   引用传参,如void fun(string& str); 如果确定str不变,必须加上const修饰。大部分时候使用引用比指针更易于代码阅读,如void fun(int* val),val修改时必须用++(*val)等类似操作

5.5)   禁止使用RTTI机制,防止switch代码到处都是,不利于维护

5.6)   auto

a)  只用于局部变量声明,如:

std::map<int, short> map1;

map1.insert(std::pair<int, short>(1, 2));

map1.insert(std::pair<int, short>(2, 3));

map1.insert(std::pair<int, short>(3, 4));

for (auto iter = map1.begin(); iter != map1.end(); ++iter) {

   cout << iter->first << " " << iter->second << endl;

}

b)  为便于阅读,当声明与使用相隔较远时,请使用变量类型全称,如

std::map<int, short> map1;

………………………………

………………………………

………………………………

std::map<int, short>::iterator iter = map1.find(1);

六、协议

a)  协议号,C2S采用奇数,S2C采用偶数,按自增顺序定义

b)  每一个servlet对应的协议号需分段处理

c)  注意协议类内部成员变量类型,根据双方协定顺序读取/写入字节,以免错乱

七、注释

  遵循原则

a)  原则上应删除已废弃代码逻辑,无需保留

b)  单行注释//,放于当前行首字母位置

c)  纯文本说明,使用//,对齐对应代码

d)  多行代码块注释/*……*/,“/*”与“*/”单独一行显示 如:

/*

code

*/

八、其它

8.1   容器基本特性,分为两大类,使用时应合理选择

a)  顺序容器:vector、list、deque、string、stack、queue、priority queues,其中后三个为适配器

b)  关联容器:set、multiset、map、multimap、bitset、hash_set、hash_map、hash_multiset、hash_multimap

c)  几种常用容器比较

  数组:vector,deque

  链表:list

  红黑树:map,multimap,set,multiset

  8.2 boost库使用shared_ptr时应注意 

a)   循环引用时需引入weak_ptr,防止因循环引用而导致的内存泄漏问题

b)  不可在调用函数中直接new,如func(shared_ptr<int>(new int), g());不同编译器执行的参数顺序可能不同,如果g()发生异常就有可能会出现内存泄漏

c)   初始化的时候必须new出一个对象,不可两个智能指针使用同一个对象初始化,正确写法:

boost::shared_ptr<A> p1(new A);

boost::shared_ptr<A> p2(new A);

错误写法:

A* a = new A;

boost::shared_ptr<A> p1(a);

boost::shared_ptr<A> p2(a);

造成2次析构

             

8.3 boost类型转化函数boost::lexical_cast使用

boost::lexical_cast<char>(str),char本身就只存储一个字符,如果str多于一个字符会转化失败,如str=”10”,正确写法char c = boost::lexical_cast<int>(“10”);

原文地址:https://www.cnblogs.com/Lucky-qin2013/p/6274984.html