(1)const用于定义常量:const定义的常量编译器可以对其进行数据静态类型安全检查。
(2)const修饰函数形式参数:当输入参数为用户自定义类型和抽象数据类型时,应该将“值传递”改为“const &传递”,可以提高效率。比较下面两段代码:
void f(A a);
void f(A const &a);
第一个函数效率低。函数体内产生A类型的临时对象用于复制参数a,临时对象的构造、复制、析构过程都将消耗时间。
而第二个函数提高了效率。用“引用传递”不需要产生临时对象,省了临时对象的构造、复制、析构过程消耗的时间。但光用引用有可能改变a,所以加const
(3)const修饰函数的返回值:如给“指针传递”的函数返回值加const,则返回值不能被直接修改,且该返回值只能被赋值给加const修饰的同类型指针。例如:
const char *GetChar(void){};
错误的:char *ch = GetChar();
正确的: const char *ch = GetChar();
但是,string s = GetChar();这样却是可以的。这样只是把GetChar()返回的指针指向的字符串拷贝一份给s对象而已,不会改变GetChar()的返回值所指向的数据。
const修饰类成员:
//a.h
class A
{
public:
A(int id);
~A();
int getID()const; //const成员函数的声明,其定义也要带const关键字
void testFun();
void print(); //重载
void print()const; //重载,用const限制的成员函数可以实现与非const成员函数的重载。
private:
const int id; //任何函数都不能对const数据成员赋值。构造函数对const数据成员进行初始化,只能通过初始化列表。
int test;
};
const成员函数里面能调用该类的非const数据成员,但是不能更改非const数据成员的值,当然也不可以更改const数据成员的值。
引申:可以在const成员函数内部新建一个该成员函数所属类类型(这里暂且称为同类类型)的局部对象,并可以访问该对象的私有成员,而且可以更改该对象的非const数据成员。
再引申:可以在所有成员函数里面访问该类的私有数据成员,也可以访问在该成员函数里面新建的同类类型的局部对象的私有成员。
const成员函数里面不能调用该类的非const成员函数,因为非const成员函数有修改成员数据的值的可能。(注意区分const成员函数与返回const值的成员函数)。
非const成员函数里面可以访问const数据成员和const成员函数,但是不能改任何声明为const的数据成员的值。
//a.cpp
A::A(int id):id(id){}
A::~A(){};
void A::testFun(){}
void A::print(){}
void A::print()const{}//这里的const关键字不能漏
int A::getID()const //这里的const关键字不能漏
{
cout<<id<<endl; //可以调用const数据成员id没问题。
//id = 2; //错误,不能改变const数据成员变量的值。
cout<<test<<endl; //可以调用非const数据成员test没问题。
//test = 3; //错误,不能改变非const数据成员变量的值。
//testFun(); //错误,不能调用非const成员函数。
print(); //这里它会调用哪个print()函数呢? 经测试,这里会调用有关键字const修饰的print()成员函数;
}
const A a(1); //声明一个常对象a;利用构造函数初始化列表,初始化const数据成员id值为1;
A b(2); //声明一个非常对象b;利用构造函数初始化列表,初始化const数据成员id值为2;
a.print();//调用的是带有关键字const的常成员函数;
b.print();//调用的是没带const关键字的成员函数;
a.testFun();//错误,常对象不能调用非const成员函数
a.getID();//正确
b.getID();//也正确,非常对象也可以调用const成员函数。
对象a只能调用它的常成员函数也就是const成员函数,而不能调用它的其他成员函数(这是C++从语法机制上对常对象的保护,也是常对象唯一的对外接口方式)
总结:
也就是说,const成员函数可以调用所有的数据成员,但不能修改;const成员函数不能调用非const成员函数。
任何函数都不能对const数据成员赋值。构造函数对const数据成员进行初始化,只能通过初始化列表。