对那些不会改变对象状态的函数,都应当将其声明为常成员函数、那么,什么是改变对象状态呢?
按照语言要求,凡是会改变非静态的成员对象值的成员函数,都不能够声明为常成员函数。但是这并不意味着,凡是不会改变非静态成员对象的成员函数,都不会改变对象的状态。 思考下,如果不改变任何一个成员对象的值,怎么会改变对象状态呢?
另一种意外情况,如果一个函数会改变某个成员对象的值,但他未必会改变对象的状态。成员状态的改变,并不能够完全根据成员对象的值是否被改变来判定,而应当根据通过这个对象对外接口所反映出的信息来判断。 如果对一个成员函数的调用,不会使得其后对该对象的接口调用的结果发生变化,那么就可以认为这个成员函数不会改变对象的状态。
class Line
{
public:
Line(const Point p1, const Point p2) :p1(p1), p2(p2), len(-1) {};
double getLen();
private:
Point p1, p2;
double len;
};
double Line::getLen()
{
if (len < 0) {
double x = p1.getX() - p2.getX();
double y = p1.getY() - p2.getY();
len = sqrt(x *x + y*y);
}
return len;
}
getLen函数只改变了len的值,而Line所表示的线段的状态,只由他的两个端点p1和p2决定,线段的长度依赖于它的端点位置,len成员只是用来将线段长度暂时记录下来,使得下次无需从新计算,因此改变len的值不会导致对象的状态改变。
这样问题就出现了。既然调用getLen不会改变对象状态,就应当将其声明为常成员函数,然而,语言上不允许,因为它会改变数据成员len的值。需要用到新的关键词—mutable。对于这类数据成员,可以使用mutable关键字加以修饰,这样,及时在常成员函数中。也可以修改他们的值、
class Line
{
public:
Line(const Point p1, const Point p2) :p1(p1), p2(p2), len(-1) {};
double getLen() const;
private:
Point p1, p2;
mutable double len;
};
double Line::getLen() const
{
if (len < 0) {
double x = p1.getX() - p2.getX();
double y = p1.getY() - p2.getY();
len = sqrt(x *x + y*y);
}
return len;
}
其实mutable不只允许在常成员函数中修改被它修饰的数据成员,被mutable修饰的成员对象在任何时候都不会被视为常对象。
参考文献《C++语言程序设计》 清华大学 郑莉老师