一.简介
const是C++中灰常灰常强大的关键字。const--constant的缩写,简单理解就是不变的意思,它的所有功能都是限定我们修改某个变量。虽然我们最熟悉的是const常量,但是这并不是const最有用的部分。const和函数碰撞在一起的时候,才能激发出const真正能力。
下面看一下const修饰函数本身,修饰函数参数,修饰函数返回值时,都能带来哪些效果。
二.const修饰函数本身
const修饰函数本身,这个是最灵活,也是最复杂,涉及到点最多的地方!!
1.const修饰函数的意义
C++中成员函数后面经常看到const关键字修饰,这是一种很好的习惯吗,在我们的函数不需要修改对象的内容时,果断给它加上const修饰。《Effective C++》中说过,尽量使用const,可以减少很多不必要的麻烦。那么const修饰成员函数究竟有什么作用呢?
a.最主要的就是防止成员函数修改成员变量(非静态成员变量):试想一下,本来我想通过这个函数来输出一下log的,但是一不小心,将判断成员变量的==写成了=,那么如果这个函数是const的,编译的时候会立刻报错的,而如果这个函数不是const的,那么这个函数就会将成员变量修改,(VS貌似会有warning),这将是一个灰常难以发现的bug。所以,当一个函数不应该修改成员变量的时候,果断将其设置为const的。
b.成员函数是不是用const修饰的,也可以很方便的帮助我们理解代码:让我们知道哪些内容可以修改对象成员的变量,哪些不可以,进而更好的帮我们理对象的功能。
c.const成员函数使我们可以操作const对象:因为非const成员函数是不能被const对象调用的,只有被声明为const的成员函数才能被一个const类对象调用。这也是C++通过指针或者引用传递参数的基础之一。
2.const修饰函数的使用方法
其实使用const修饰函数很简单,只需要在函数后面加上一个const即可。不过有一点要注意,当函数定义和声明分开的时候,如果声明加了const,那么定义的时候也需要加上const,这一点与virtual关键字不同。
简单的一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class Base
{
private:
int num;
public:
Base(int n)
{
num = n;
}
virtual void Show() const ;
};
void Base::Show() const
{
cout<<"base show: "<<num<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
Base* base1 = new Base(1);
base1->Show();
system("pause");
return 0;
}
结果:
base show: 1
请按任意键继续. . .
请按任意键继续. . .
3.加const和不加const表示不同的函数
我们还是用virtual关键字作为比较,当这个类被继承之后,原本为virtual的函数,在子类中即使不写virtual,它仍然是virtual的。但是,我们如果不写const的话,会发生什么呢?这可是一个灰常有意思的实验,瞪大眼睛看好啦!!!
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
//基类,包含一个virtual函数,const类型
class Base
{
protected:
int num;
public:
Base(int n)
{
num = n;
}
virtual void Show() const ;
};
void Base::Show() const
{
cout<<"base show: "<<num<<endl;
}
//派生类,派生了Show,但是!!!忘记写const了
class Derived : public Base
{
public:
Derived(int n) : Base(n)
{
}
void Show();
};
void Derived::Show()
{
cout<<"derived show: "<<num<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
//基类调用基类,base show木有问题
Base* base1 = new Base(1);
base1->Show();
//基类掉子类,应该触发多态,derived show会被调用吗?
Base* derived1 = new Derived(2);
derived1->Show();
system("pause");
return 0;
}
结果:
base show: 1
base show: 2
请按任意键继续. . .
base show: 2
请按任意键继续. . .
virtual函数,正常应该触发多态的,但是!!并没有出现我们想要的结果!!!derived1调用的仍然是基类的Show方法。为什么会出现这种情况呢?原因很简单,virtual并没有失效,而是因为我们根本就没有覆写Show()const函数!!!换句话说,我们在子类又创建了一个非const版本的Show函数!而我们调用的时候,直接调用了基类的Show,跟virtual没有半毛钱关系。
virtual等其他关键字,修饰之后,函数仍然是原来的函数,定义一个不带这个关键字的函数就会报错说重定义。但是,const关键字和它们不一样,有const和没有const的函数是两个不同的函数,它们是可以共存的!!
上面的例子主要就是说明const版本的成员函数和非const版本的成员函数并不相同,说实话绕的有点儿远,不过这个确实是一个非常容易犯的错误,而又非常非常难以发现!本人亲测,在VS默认警告等级上,并没有给出警告。将警告等级调高之后,编译器才给出了警告: