在自定义类型前加入const修饰符,可以将对象声明为常对象(如const MyClass A)。自定义类型的const常量不仅像基本数据类型那样不可以作左值,而且const对象的任意成员变量也不能被修改(mutable成员变量除外),为了保证const对象成员变量不能被修改,C++中规定了const对象只能调用一种特殊的成员函数——const成员函数。所谓const成员函数,就是不修改对象中任何一个变量的成员函数(mutable成员变量除外),但是不修改成员变量的函数不一定就是const成员函数。不修改任何成员变量的值的成员函数有资格成为const成员函数。有资格成为const成员函数的成员函数在函数首部的参数列表后加入const限定符,该成员函数成为const成员函数。在修改了非mutable成员变量的成员函数的参数列表后加入const限定符是编译错误。
相同函数名、相同参数列表的const成员函数与非const成员函数是重载关系。对象调用成员函数的原则是:const对象只能调用const成员函数,非cosnt对象既能调用非const成员函数,又能调用const成员函数,如果同名同参数列表的const成员函数与非const成员函数同时存在(重载),非cosnt对象调用非const成员函数。
由于const对象和非const对象都要调用构造函数和析构函数,因此构造函数和析构函数没有const函数与非const函数的区分。如果构造函数或析构函数中调用了同类的某个非const成员函数,不会影响const对象对该构造函数或析构函数的调用。
#include<iostream>
using std::cout;
using std::endl;
class Time
{
public:
Time(int h=0,int m=0,int s=0)
{
set_hour(h);
set_minute(m);
set_second(s);
}
void set_hour(int h)//非const成员函数
{
hour=h>=0&&h<=23?h:0;
}
void set_minute(int m)//非const成员函数
{
minute=m>=0&&m<=59?m:0;
}
void set_second(int s)//非const成员函数
{
second=s>=0&&s<=59?s:0;
}
int get_hour()const //const成员函数
{
return hour;
}
int get_minute() //有资格成为const成员函数,但不是const成员函数
{
return minute;
}
int get_second()const //const成员函数
{
cout<<"const成员函数get_second()const被调用"<<endl;
return second;
}
int get_second() //非const成员函数
{
cout<<"非const成员函数get_second()被调用"<<endl;
return second;
}
private:
int hour;
int minute;
int second;
};
int main()
{
Time afternoon(14,0,0);//非const对象
int h=afternoon.get_hour();//非const对象调用const成员函数
int m=afternoon.get_minute();//非const对象调用非const成员函数
int s=afternoon.get_second();//非const对象调用非const成员函数
cout<<"afternoon="<<h<<":"<<m<<":"<<s<<endl;
afternoon.set_hour(15);//修改非const对象
cout<<"afternoon.hour="<<afternoon.get_hour()<<endl;
const Time noon(12,0,0);//const对象
h=noon.get_hour();//const对象调用const成员函数
//m=noon.get_minute();错误,const对象调用非const成员函数
s=noon.get_second();//const对象调用const成员函数
cout<<"noon="<<h<<":XX:"<<s<<endl;
return 0;
}
显示结果:
非const成员函数get_second()被调用
afternoon=14:0:0
afternoon.hour=15
const成员函数get_second()const被调用
noon=12:XX:0
程序的类型Time包括hour、minute和second等3个成员变量和构造函数、set_hour、set_minute、set_second、get_hour、get_minute以及2个版本的get_second等成员函数。其中set_hour、set_minute和set_second分别用于设置成员变量hour、minute和second的值,这3个成员函数修改成员变量的值,所以它们没有资格成为const成员函数,如果将它们声明为const成员函数(参数列表后加const关键字)将出现编译错误,构造函数中调用了这3个非const成员函数。函数get_hour、get_minute和get_second都没有修改任何成员变量的值,它们都有资格成为const成员函数。这里我们把get_hour声明为const成员函数(第27行),故意把get_minute声明为非const成员函数(第31行),同时把get_second声明为const和非const两个版本的成员函数(第35、40行)。
main函数中声明了Time类的非const对象afternoon(第52行),通过程序的显示结果可以看出,非const对象可以调用非const成员函数(第54、57行),也可以调用const成员函数(第53、58行),当调用const和非const两个版本同时存在的成员函数get_second时,非const对象调用非const版本的成员函数(第55行)。
main函数中又声明了Time类的const对象noon(第60行),虽然构造函数中调用了非const成员函数set_hour、set_minute和set_second,但是这并不影响const对象对构造函数的调用。通过程序的显示结果可以看出,const对象只可以调用const成员函数(第61、63行),不可以调用非const成员函数,哪怕该成员函数没有修改成员变量的值(第62行),当调用const和非const两个版本同时存在的成员函数get_second时,const对象调用const版本的成员函数(第63行)。
另外,成员函数get_minute没有修改成员变量的值,但程序中却没有把它声明为const成员函数,造成了本应该能调用它的const对象无法调用该函数。因此,在编写自定义类型时,我们应该把那些没有修改成员变量的成员函数声明为const成员函数。