@[toc]
一、命名规范
每个公司都有不同的代码规范,列举两种比较常用的规范。
1.1 小驼峰式命名法(lower camel case):
第一个单词以小写字母开始,第二个单词的首字母大写。例如:firstName
、lastName
。
1.2 大驼峰式命名法(upper camel case):
每一个单词的首字母都采用大写字母,例如:FirstName、LastName、CamelCase
,也被称为Pascal
命名法。变种:StudlyCaps
,是“驼峰式大小写”的变种.
二、不确定的函数访问权限声明为私有
新增一个函数,在不确定其使用范围时,使用private
限定。
- 降低调用人查找外部接口的负担
- 未使用的
private
函数可以被SonarQube
检测出来,并列举到代码坏味道中,方便后续精简结构。 - 保证类层次和封闭性
三、条件判断时常值放左边
条件判断等号==
,在输入时肯可能因为键盘问题或其他不可控的疏忽,导致漏掉一个等号字符,成为正常的赋值语句。正常编译,运行时候错误难排查。因此要求将常值放在等号左边,即使漏掉一个等号,因常值无法赋值修改,编译期间会报错。
string strvalue = "loveyy"
//如果写成了(strvalue="loveyy"),变成赋值语句,不会报错
if(strvalue == "loveyy")
{
//..
}
//如果写成了("loveyy"=strvalue),会编译报错
if("loveyy" == strvalue)
{
//...
}
三、分支和循环后的单行语句置于花括号
if,else,for,while
等分支和循环语句,后跟单行语句时,花括号虽然可以省略,但可能因为意想不到的宏展开导致错误,或由于后续维护增加代码和不当操作,引起其他错误。
//如果REPORT宏展开以后是多行,可能会引起错误
#define REPORT(value) \
cout<<value<<endl;\
cout<<value<<endl;
//错误写法
if("lovepigyy" == str_Value)
REPORT("PIGYUANYUAN");
//宏展开后
if("lovepigyy" == str_Value)
cout<<"PIGYUANYUAN"<<endl;
cout<<"PIGYUANYUAN"<<endl;
//正确写法
if("lovepigyy" == str_Value)
{
REPORT("PIGYUANYUAN");}
//宏展开后
if("lovepigyy" == str_Value)
{
cout<<"PIGYUANYUAN"<<endl;
cout<<"PIGYUANYUAN"<<endl;
}
四、重写虚函数需要添加override关键字
在派生类中重写基类的虚函数,如果重写函数没有添加override
关键字,在函数名称或参数书写错误的情况下,编译时,会创建一个新的虚函数,编译不报错,运行时,不能正确的实现动态多态,且在代码量大时很难定位,难以察觉。
派生类中的虚函数声明处,添加override
关键字能够保证与父类的虚函数声明的一致性检查,确认其父类一定包含此虚函数,在不一致时候,会编译报错。
class Base
{
//...
protected:
virtual void Update();
};
class Derivated : public Base
{
//...
protected:
virtual void Update() override;
}
五、 类成员变量在声明处设置默认值
类成员变量未定义,或因存在多种构造函数,在某次构造时忘记初始化,尤其是指针变量,很容易引起错误。
避免忘记初始化,在头文件变量声明处一定要赋值。
class My_CLass
{
//...
private:
My_CLass1 *m_mylp{
nullptr };
bool m_firstRead{
false };
}
六、 类析构函数中释放类型为指针的成员变量
避免内存泄露,程序运行越久,占用内存越大的问题。struct
除默认访问方式,继承方式以及关键字的用处不同,其他与class
等价
class My_Class
{
//...
~My_CLass()
{
if(!ptr)
{
delete ptr;
ptr = nullptr;
}
}
//...
private:
My_CLass* ptr{
nullptr};
}
六、使用nullptr而不是NULL、0
参考链接爱编程的大饼
//底层代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
也就是说如果源码是 C++
程序 NULL
就是 0,如果是 C
程序NULL
表示(void*)0
。那么为什么要这样做呢? 是由于C++
中,void *
类型无法隐式转换为其他类型的指针,此时使用 0
代替((void *)0)
,用于解决空指针的问题。这个 0(0x0000 0000)
表示的就是虚拟地址空间中的0
地址,这块地址是只读的。
出于兼容性的考虑,C++11
标准并没有对 NULL
的宏定义做任何修改,而是另其炉灶,引入了一个新的关键字 nullptr
。nullptr
专用于初始化空类型指针,不同类型的指针变量都可以使用 nullptr
来初始化
void fun(int)
void fun(int*)
fun(nullptr);//调用fun(int *)
//如果是:
fun(NULL);//调用fun(int)
七、非基础类型参数传递尽量使用const
修饰的引用
防止参数传递过程中多义词拷贝构造和析构,尽量使用const
和引用
- 避免拷贝构造构造造成额外的开销和程序效率变低。
- 避免函数体中意外修改,编译时报错。
my_calss* Get_Name(const std::string & name);
注:基础类型的如(int
,float
),不建议传递引用会导致效率更低,另外STL迭代器
和函数对象也使用值传递。