第1版:https://blog.csdn.net/acebdo/article/details/20643503
第1版写于4年前,在这期间我也写了很多代码,在实际应用中发现很多不足,所以对第1版进行修改和扩充。
偷懒原则1
有时候为了偷工减料,可以使用一些比较短的名字。
double f算圆面积(double r) {//半径r
return r * r * pi;//圆周率pi
}
void f什么也没发生() {
for (int i = 0; i != 10; ++i);//计数i
}
偷懒的名称必须清晰易懂,看到变量名就容易想到具体用途,尽量用在类/结构/函数内部。如果容易忘记变量用途,那就写完整名称,或者加注释,加注释的方法仅限函数局部变量和函数参数。
一些常见的可以偷懒的命名:
- 用于循环的i、j、k
- 表示限制/数量的n
- 异常处理中的e
一些约定俗成的名称也遵循偷懒原则:
- python中表示对象自身的self
自定义类型
全部用大写的英文单词首字母作为前缀:类C(class),结构S(struct),接口I(interface),联合U(union),窗口W(window)。
struct S结构 {};
class C类 {};
union U联合 {};
异常类X(打叉)
class X未实现 : public std::runtime_error {
public:
X未实现(): std::runtime_error("该函数未实现") {}
};
枚举
枚举类型用E(enum),枚举值用e(enum)。
enum E状态 {
e好,
e坏,
e不好不坏
};
函数
函数用f(function)
void f计算() {}
声明函数时,函数形参不用加前缀。因为这里的参数名就跟注释一样的仅供参考。
double f算圆面积(double 半径);
对于函数类和创建函数对象的函数,用大写的F
template<typename t>
struct F小于 {
operator()(const t &a0, const t &a1) const {
return a0 < a1;
}
};
std::function<int()> F返回整数(int a) {
return [=]()->int {
return a;
};
}
const std::function<int()> f返回1 = F返回整数(1);
函数的二级前缀
根据函数功能的不同,使用不同的二级前缀,只用一个字符:
创建c(create/construct)
class C工厂 {
std::shared_ptr<C人> fc人();//造人
}
因为c是创建(create)和构造(construct)的缩写,所以c也可以表示构造自身。为了区分是创建其他对象还是自己创建自己,我对类和结构的“fc”进行限制:类中的fc用于创建其他对象,结构的fc用于创建自己。
例如:二维向量结构
struct S向量2 {//二维向量
double x = 0, y = 0;
S向量2() = default;
S向量2(double X, double Y);//直接给x,y赋值
static S向量2 fc大小方向(double 大小, double 方向);//根据大小方向计算x,y
}
获取g(get)/设置s(set)
double fg大小();
double fg方向();
void fs大小(double);
void fs方向(double);
判断是/否的i(is)
bool fi创建() const;
bool fi有效() const;
转换到某个类型用t(to)
struct S向量2 {
double x = 0, y = 0;
S向量3 ft向量3(double z = 0) {
return {x, y, z};
}
}
枚举e(enumerate),表示该函数支持简单迭代。
def fe零到几(a: int):
for i in range(a):
yield i
class C人群 {
private List<C人> ma人;
public IEnumerable<C人> fe活人() {
foreach (C人 v人 in ma人) {
if (v人.fi存活()) {
yield return v人;
}
}
}
}
函数的二级前缀只能用动词,不能用名词,用名词容易跟动词混淆。
变量/常量
变量v(variable),全局变量g(global),函数参数a(argument),类/结构成员变量m(member),编译期常量c(constant),窗口控件w(window/widget)
如果不知道一个变量该用什么前缀,就用v吧。
示例:人类
class C人 {
public:
std::string m姓名;
int m年龄;
}
示例:函数
constexpr double c圆周率 = 3.1415926;
double f加圆周率(double a) {
const double v = a + c圆周率;
return v;
}
示例:全局变量+单例类
int g大家都可以访问 = 0;
class C单例 {
static C单例 *g这;
C单例() {
assert(g这 == nullptr);
g这 = this;
}
};
C单例 *C单例::g这 = nullptr;
我觉得没必要用s(static)来表示静态变量,因为静态变量还要按访问权限继续细分,不然只有个s容易混淆(虽然静态函数和成员函数都用f也很容易混淆),而且静态变量的使用频率没其他变量那么频繁。所以我对公有静态变量用g,私有静态变量用m,局部静态变量用v。
设计用户界面给控件命名可以用w,HTML的元素id也可以用w。
w的定义比较模糊,容易和其他一级前缀和变量的二级前缀混淆
<input id="w姓名" class="W文本框" type="text"/>
<input id="w年龄" class="W文本框" type="text"/>
<textarea id="w备注" class="W文本框" rows="5"></textarea>
变量的二级前缀
根据变量的功能/类型可以再加二级前缀。使用类型作为变量的二级前缀时,必须是广泛使用的类型,比如指针p、数组a、函数f。
是否i,和前面一样
void f强行成功() {
mi成功 = true;
}
bool fi成功() {
return mi成功;
}
指针p。句柄也用p,因为句柄是特殊的指针。
int *vp整数 = new int();
std::shared_ptr<int> vp还是整数 = std::make_shared<int>();
HWND vp窗口 = nullptr;
函数指针f,c#的委托也可以用这个
std::function<void(std::function<void()>)> vf = [](std::function<void()> af) {
af();
}
数组a(array)。像其他包含多个变量的容器也用a作为前缀,例如:列表、元祖、字典、集合。
std::vector<S学生> va学生;
不要学匈牙利命名法i、n、w、sz、str、h这种前缀。
类型别名
类型别名用t,同时可以根据具体类型添加二级前缀
typedef S向量2 t向量2;
typedef int *tp整数;
typedef ComPtr<ID3D12Device> tp设备;
typedef std::shared_ptr<I工厂> tp工厂;
typedef std::function<void()> tf;
模板参数也用t
template<typename t> void f(const t &) {
}
可变参数模板中懒得想名字可直接取名“参数”
template<typename...t参数>
void f(t参数 &&...a参数);
重名的处理方法(序号后缀)
虽然前面写了一堆前缀,但实际应用中还是会出现重名。
比如:出现了功能和前面一样的临时变量
bool f判断(C判断 a判断) {
C判断 v判断 = a判断;
{//为了满足文章需求强行定义临时变量
C判断 v判断;//重复了
}
return v判断.m判断;
}
上面有2个“v判断”,虽然编译不会出错,但是局部作用域需要用到第1个“v判断”呢?这时候在变量名后面加数字区分,从0开始。
C判断 v判断0 = a判断;
{
C判断 v判断1 = v判断0;
}
在循环中也可以加数字区分
for (int i0 = 0; i0 != 10; ++i0) {
for (int i1 = 0; i1 != 10; ++i1) {
}
}
序号后缀法用于函数时,仅限在类内部使用,因为公开的函数给别人用的话容易搞不清楚函数0123的具体作用以及他们的区别。如果真的重复了想不出别的名字了,见后面的命名分类。
偷懒原则2
偷懒原则2:根据类型名就可以知道用途,且没有其他变量/参数时,可以只写前缀,省略中文名。
void f(C干一件大事 a) {//不用写中文也知道a是用来干一件大事的
C干一件大事 v;//不用写中文也知道v是用来干一件大事的
}
往排序函数扔比较函数时,比较函数中的参数名也省略
std::sort(va人.begin(), va人.end(), [](const C人 &a0, const C人 &a1) {
return a0.m年龄 < a1.m年龄;
});
偷懒原则1与偷懒原则2不能同时使用,因为容易造成歧义。
偷懒原则2只限局部变量/参数使用
避免意思重复的名称
就像“凯旋归来”这个充满争议的病句一样,不要存在意思重复的命名。
比如“va数组变量”这个就反了意思重复的错误,v表示变量,a表示数组,后面再加个“数组变量”就重复了。就算不知道取什么名字也不能取意思重复的词,命名成“va东西”也行,或者根据偷懒原则2直接命名“va”。
再比如异常类的前缀X,既然X代表了异常,就不要在名称中加“异常”、“错误”什么的。
1.5级前缀:命名分类
有时候定义的变量名、函数名太多了,有时候类中对外开放的函数和内部使用的函数名称一样,这时候使用命名分类区分不同函数的功能/作用范围
命名分类直接写“中文名_”
class I加减 {
virtual int f接口_加() = 0;
virturl int f接口_减() = 0;
};
class C加 : public I加 {
public:
int f接口_加() override;
int f接口_减() override;
private:
int f内部_加0();
int f内部_加1();
int f内部_减();
}
版本后缀
版本后缀用来区分功能相似但版本不同的函数。
版本后缀有2种写法:第一种直接加英文字母,第二种加下划线再写中文的“_版本名”
例如:“S向量2::fc大小方向”按平面角单位分度、弧度版本
static S向量2 fc大小方向r(double 大小, double 弧度);
static S向量2 fc大小方向d(double 大小, double 度);
例如:三维坐标系中根据手性分左手坐标系和右手坐标系,根据左右手不同在函数后面加l或r。
不加一级前缀的东西
命名空间:大家不加,我也不加。
模块/包:理由同上。
宏:比较少用,所以不加。
(该文章会根据实际情况不断修改,最后更新时间:2018年8月2日)