在编写类的时候我们要非常好的把握细节问题,不只要去避免一些明显的错误,很多其它的是怎样形成良好的编程风格。以下我们将从以下的一个样例分析类的编写技巧:
class Complex
{
public:
Complex(double real,double imaginary = 0):_real(real),_imaginary(imaginary){ }
void operator+(Complex other)
{
_real =_real +other._real;
_imaginary = _imaginary + other._imaginary;
}
void operator<<(ostream os)
{
os << "(" << _real << "," << _imaginary << ")";
}
Complex operator++()
{
++_real;
return *this;
}
Complex operator++(int)
{
Complex temp = *this;
++_real;
return temp;
}
private:
double _real,_imaginary;
}
1、我们要当心在隐式类型转换中产生的隐含暂时对象。避免这个问题的一个好方法就是,尽可能的在构造函数中进行显示的类型转换,并要避免编写类型转换运算符。
因为上述类中的构造函数的第二个參数有默认值,因此这个函数也可当成是单參数的构造函数来使用,这也意味着能够进行从double类型到Complex类型的隐式转换。要注意这样的类型转换可能并不总是我们所希望的。
2、在传递參数对象时,我们应该优先选择const&的方式,而不是传值方式。比如:
void operator+(Complex other)在传递參数时将会有暂时对象的产生,运行效率会减少
3、我们应该优先选择“a op=b”这样的写法,而不是“a = a op b”(这里的op表示的是某个运算符)。这样的写法更为清晰,并且效率也更高。
为什么operator+=的效率会更高?原因就在于这个运算符是直接对其左边的对象进行运算,而且返回的是一个引用而不是暂时对象。而operator+则必须返回一个暂时对象。比如:
T& T::operator+=(const T& other)
{
//...
return *this;
}
const T operator+(const T& a,const T& b)
{
T temp(a);
temp+=b;
return temp;
}
我们要注意的是运算符+和+=之间的关系。前者是通过后者来实现的,这不仅是为了实现代码的简洁性,也是为了保证代码的一致性。注意,为了防止程序猿编写出像“a+b = c”这种表达式,所返回的暂时对象的类型应该是“const Complex”(而不是Complex),这就是为什么上面的operator+中返回的是const T的原因。
4、在C++标准中规定:必须将运算符=、( )、[ ]和->定义为成员函数,而在类中定义的new、new[]、delete和delete[]等运算符函数必须是静态成员函数。对于其它的运算符函数:假设运算符函数时用于对流进行I/O的operator>>或者operator<<;或者假设须要对其左參数进行类型转换;或者假设能够通过类的公有接口来实现,那么将这个函数定义为非成员函数(在前两种情况中,假设须要的话也能够被定义为友元函数)。假设运算符函数须要实现虚函数的行为,那么请添加一个虚成员函数来提供虚函数的行为,那么请添加一个虚成员函数来提供虚函数的行为,并用这个虚成员函数来实现运算符函数。否则将运算符函数定义为成员函数。
5、operator<< 不应该被定义为成员函数。而且,非成员函数operator<<应该使用成员函数(一般是虚函数)来实现,而且这个成员函数的功能就是进行流输出。更进一步,operator<<应该返回一个“ostream&”类型的应用,而且所应用的就是这个流对象,这是为了实现链式操作。
6、前置递增运算符应该返回一个很量的引用,这不仅使客户代码可以以更直观的方式来编写,并且还避免了不必要的低效率。在后置递增运算符函数中应该返回一个常量值。这种做法可以防止对返回的对象进行改动,从而避免了想“a++++”这种问题代码。并且为了保持代码的一致性,我们应该使用前置递增来实现后置递增。
7、要避免使用保留名字。在C++标准库的实现中保留了一些带有前导下划线的标识符,这些保留的标识符是非常难记住的,因此,最好是根本不要使用前导下划线。
经过以上的分析,我们改动后的类为:
class Complex
{
public:
explicit Complex(double real,double imaginary = 0):_real(real),_imaginary(imaginary){ }
Complex& operator+=(const Complex& other)
{
_real += other._real;
_imaginary += other._imaginary;
return *this;
}
Complex& operator++()
{
++_real;
return *this;
}
const Complex operator++(int)
{
Complex temp (*this);
++_real;
return temp;
}
ostream& Print(ostream& os) const
{
return os << "(" << real_ <<","<< imaginary_ << ")";
}
private:
double real_,imaginary_;
}
const Complex operator+(const Complex& lhs,const Complex& rhs)
{
Complex ret(lhs);
ret+=rhs;
return ret;
}
ostream& operator<<(ostream& os,const Complex& c)
{
return c.Print(os);
}