数据成员的值反应了对象在程序运行某个时刻的状态。数据成员值的改变是由于对象处理了一条消息,往往是某个成员函数被调用。但是有的时候我们希望,成员函数仅仅是访问数据成员而不对其值进行修改。所以,对象的成员函数被分成了两类:
1. 修改对象状态的成员函数;
2. 获取对象状态的成员函数;
而const 成员函数就是为第2个功能而设计。尽管,只要我们在成员函数里不修改对象数据成员的值就可以认为这是一个获取对象状态
的成员函数,但是有的时候在实现的时候会无意的改变数据成员的值,所以为了起到防范的目的,C++提供了const 成员函数的机制,
即在定义一个成员函数时,给他加上const 说明,表示他是一个获取对象状态的成员函数。
定义的方式是:
在 函数名之后和函数体之前加上 const 关键词,例如下面类A中的函数 func
class A { ................... void func() const { ... } };
此时成员函数func被定义成为了const 成员函数,在函数体中不能修改数据成员的值,如果在func中改变了这些值那么编译程序就会指出这个错误,例如下面的实现
class A { int data; char *p; public: ............. void func() const { data = 10; // Error, 表达式必须是可修改的左值 p = new char[10]; // Error } };
但是,对于指针类型的变量,虽然不允许const成员函数修改指针本身,但是允许它修改指针所指向的值,如上面的func函数如果修改成以下所示:
class A { int data; char *p; public: ..................... void func() const { *p = 'A'; // 改变的是p指向的值,但是没有改变p自身,所以编译通过 strcpy(p, "abcde"); // 同上 } };
所以,在这种情况下,仍需要程序设计者自己对程序进行把握。
上面就是 const 成员函数的主要用法,下面我们来介绍它的另一个用法:
对常量对象的成员函数的合法性进行判断。
例如下面的例子:
class A { int x,y; public: void f() const {...} void g() {...} }; const A a; ............ a.f(); //ok 常量对象调用常量成员函数 a.g(); // Error.
a是常量对象,所以对常量对象的操作只能获取对象的状态,而不能改变它的状态。所以只能调用a的const 成员函数。
常量对象一般用于函数的形参类型说明,同时为了提高参数传递的效率,一般是将形参定义为对象指针或者引用,这时为了防止函数修改实参对象
可以把形参定义为常量对象指针或者常量对象引用,例如:
void f(const A *pa); 或者 void f(const A &a);
这样在函数f中就不能调用对象*pa或a的非const 成员函数;从而起到保护作用。
还有一点需要注意的是,如果将const 成员函数放在类外定义,那么函数声明和定义的地方都要加上const
class A { void f() const; //声明 }; void A::f()const { // 定义 }