最近读别人的帖子遇到一个很有趣的问题,兴趣所致便对此略微做了一些讨论。
问题大致描述如下,在类中对函数声明时加了const声明。但在类外对函数定义时把const漏掉了,最后导致编译错误。实例代码如下:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int v):_value(v){}
void showValue() const;
private:
int _value;
};
void Test::showValue()
{
cout<<_value<<endl;
}
int main()
{
const Test ct(15);
ct.showValue();
Test t(15);
t.showValue();
}
在编译的时候会提示Test类中没有找到重载的成员函数的错误。。。而在函数定义中加入const后,程序便可以正常编译运行了。OK,到这里能够理解const函数和非const函数声明是非同一个函数,它们之间是要构成函数重载的。这里引申出一个问题,但我在类中同时定义了const和非const函数时,由于他们的函数名、参数全部都是相同的,那在函数调用的时候究竟要调用哪个函数呢?通过代码来实验,对上面的对面稍微做些变动,如下:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int v):_value(v){}
void showValue() const;
void showValue();
private:
int _value;
};
void Test::showValue()const
{
cout<<_value<<endl;
}
void Test::showValue()
{
cout<<_value+1<<endl;
}
int main()
{
Test t(15);
t.showValue();
}
这里的运行结果是输出16,说明是调用了非const版本的成员函数,但在把非const版本的函数声明和函数定义去掉后,输出结果又变成了15。 这也从另一方面说明,这两个const和非const函数的确是能够成重载函数的。为了解决到底该调用哪个函数的问题,笔者查询了《C++程序设计语言》中关于函数重载调用的部分,找到关于函数重载调用的匹配部分(裘宗燕译),原文摘要如下:
[1]准确匹配:也就是说,无须任何转换或者只须做平凡转换(例如,数组名到指针,函数名到函数指针,T到const T等)的匹配
[2]利用提升的匹配:即包括整数提升(bool到int,char到int,short到int以及它们的无符号版本),以及从float到double的提升
[3]利用标准的转换(例如,int到double,double到int,double到long double,Derived*到Base*,T*到void*,int到unsigned int)的匹配
[4]利用用户定义转换的匹配
[5]利用在函数声明中省略号…的匹配
这里的级别是从高往低的,如果在能找到匹配的某个最高的层次上同时发现两个匹配,这个调用将作为存在歧义而被拒绝
回到最初的问题,调用const和非const函数的时候,到底是如何进行区分的呢?根据这里的匹配规则,似乎两个匹配都能在规则1中匹配到,但是调用动作却被允许了。根据规则1,笔者猜想,const函数的调用可能是优先匹配const数据类型的,于是定义一个const对象,const Test ct(15);在ct对象调用showValue()函数的时候,输出的结果的确是15.
代码如下:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int v):_value(v){}
void showValue() const;
void showValue();
private:
int _value;
};
void Test::showValue()const
{
cout<<_value<<endl;
}
void Test::showValue()
{
cout<<_value+1<<endl;
}
int main()
{
Test t(15);
t.showValue();
const Test ct(15);
ct.showValue();
}
程序运行结果如下,不过还是不能理解为何这里没有提示冲突。。。。。。