目录标题
- 1.背景
- 2.正文
- 2.1 构造函数尽量使用initialization list
- 2.2 思考函数需不需要添加const
- 2.3 参数传递尽量使用pass-by-reference
- 2.4 参数返回尽量使用return-by-reference
- 2.5 数据的访问权限尽量用private,函数用public
- 3.结语
1.背景
最近在学习侯捷老师的C++课程,该博文是对课程中一些关于类设计的准则提炼。适用于初级学习者。用侯捷老师的话,一个鲁棒性、优雅性比较高的C++代码应该注意这些细节。
2.正文
2.1 构造函数尽量使用initialization list
尽量采用
public:
complex (double r = 0, double i = 0)
: re(r), im(i)
{}
而不要采用
public:
complex (double r = 0, double i = 0)
{re = r; im = i;}
2.2 思考函数需不需要添加const
如果该成员函数会改变成员变量,则不添加const关键字,否则尽量添加。例如, 思考之后,认为real()和imag()函数需要添加const关键字:
double real() const {return re;}
double imag() const {return im;}
在该类调用的过程中可能会存在如下两种情形:
// 调用方式1
{
complex c1(2, 1);
cout << c1.real();
cout << c1.imag();
}
// 调用方式2
{
const complex c1(2, 1);
cout << c1.real();
cout << c1.image();
}
此时由于注意了const这一细节的设计,无论调用者如何调用都是可以的。但如果在类设计的过程中,没有在real()函数和imag()函数之后添加const关键字,则上述调用方式2是会出问题的。原因在于调用者通过const complex表明希望施加于complex对象上的任何操作都一定(!!!)不可以改变其成员变量。而编译器看到类在定义成员函数的过程中无const标志,会认为该函数有改变成员变量的可能,不满足调用者一定不可以改变的要求,从而报错。这里补充一点,编译器只会简单的根据const标志的有无来判断该函数的行为,不会智能到分析成员函数内部的实际操作是否真的改变成员变量。
2.3 参数传递尽量使用pass-by-reference
complex& operator += (const complex&);
尽可能的采用pass-by-reference。这样可以带来一个好处:效率高,节省了pass-by-value方式中隐含的copy操作。同时,也会带来另外一个特性(谈不上好或坏):函数内部对该变量的修改会影响到函数外部。如果想禁止被修改,仅利用效率高的优点,可以显式的在形参上追加const关键字来表明意图。
2.4 参数返回尽量使用return-by-reference
return-by-reference的形式如下所示:
inline complex&
__doapl(complex* ths, const complex& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
return-by-reference同样可以节省return-by-value隐含的赋值操作,从而提高效率。但注意:return-by-reference返回的变量一定不能是局部变量,因为局部变量的生命周期有限,以成员函数为例,局部变量出了成员函数,就会被销毁。
2.5 数据的访问权限尽量用private,函数用public
变量尽量采用private,不要让类外部有访问的权限。如果要访问该数据,也要单独的为其设计一个类内函数来“繁琐”的获取。
public:
double real() const {return re;}
double imag() const {return imag;}
private:
double re, im;
3.结语
侯捷老师通过课程为我们总结了这五条C++类设计的准则。作为初学者,感觉可以先不求甚解的记忆下来。另一方面自己的感触是,不要随意的去看非正规军撰写的C++代码,因为极有可能C++代码写的并不完备,也即没有采用这些准则。会让自己的认知变得混乱。