您的位置:首页 > 编程语言 > C语言/C++

C++中成员函数的重载、覆盖与隐藏

2010-08-01 18:47 465 查看
首先阐述一下各自的定义:

一、重载

1、范围相同(在同一个类里,不能跨类)。

2、函数名字相同。

3、参数不同。

4、virtual 关键字可有可无。

二、覆盖

1、范围不同(派生类与基类)。

2、函数名相同。

3、参数相同。

4、基类必须有 virtual 关键字。

三、隐藏

隐藏分两种情况:

(1)

1、范围不同(派生类与基类)。

2、函数名字相同。

3、参数不同。

4、virtual 关键字可有可无。

(2)

1、范围不同(派生类与基类)。

2、函数名相同。

3、参数相同。

4、基类没有 virtual 关键字。

下面我们看看重载和覆盖的示例:

#include <iostream>
using namespace std;

class CBase
{
public:
void f(int x) { cout<<"CBase::f(int)"<<" "<<x<<endl; }
void f(float x) { cout<<"CBase::f(float)"<<" "<<x<<endl; }
virtual void g(void) { cout<<"CBase::g(void)"<<endl; }
};

class CDerived:public CBase
{
public:
virtual void g(void) { cout<<"CDerived::g(void)"<<endl; }
};

int main(int argc, char* argv[])
{
CDerived d;
CBase *pBase=&d;

pBase->f(10);
pBase->f(10.10f);
pBase->g();

return 0;
}

输出的结果为:

CBase::f(int) 10

CBase::f(int) 10.1

CDerived::g(void)

这说明子类的 g(void) 函数覆盖了父类的 g(void)。

再看看覆盖和隐藏的示例:

#include <iostream>
using namespace std;

class CBase
{
public:
virtual void f(float x) { cout<<"CBase::f(float)"<<" "<<x<<endl; }
void g(float x) { cout<<"CBase::g(float)"<<" "<<x<<endl; }
void h(float x) { cout<<"CBase::h(float)"<<" "<<x<<endl; }
};

class CDerived:public CBase
{
public:
virtual void f(float x) { cout<<"CDerived::f(float)"<<" "<<x<<endl; }
void g(int x) { cout<<"CDerived::g(int)"<<" "<<x<<endl; }
void h(float x) { cout<<"CDerived::h(float)"<<" "<<x<<endl; }
};

int main(int argc, char* argv[])
{
CDerived d;
CBase *pBase=&d;
CDerived *pDerived=&d;

pBase->f(20.20f);
pDerived->f(20.20f);

pBase->g(30.30f);
pDerived->g(30.30f);

pBase->h(40.40f);
pDerived->h(40.40f);

return 0;
}

输出的结果为:

CDerived::f(float) 20.2

CDerived::f(float) 20.2

CBase::g(float) 30.3

CDerived::g(int) 30

CBase::h(float) 40.4

CDerived::h(float) 40.4

上面的例子中 子类 CDerived 的函数 f(float) 覆盖了父类的 f(float)

函数 g 和 f 依赖于指针的类型,如果是子类的指针,则隐藏了父类的函数。

隐藏的麻烦和解决办法:

#include <iostream>
using namespace std;

class CBase
{
public:
void f(int x) { cout<<"CBase::f(int)"<<" "<<x<<endl; }
};

class CDerived:public CBase
{
public:
void f(char *str) { cout<<"CDerived::f(char*)"<<" "<<str<<endl; }、
};

int main(int argc, char* argv[])
{
CDerived *pd=new CDerived;
pd->f(100); // error

return 0;
}

说明:语句 pd->f(100); 的本意是调用 CBase::f(int),但是 CBase::f(int) 不幸被 CDerived::f(char*) 隐藏了。由于数字 100 不能被隐式的转换为字符串,所以编译出错。

隐藏规则至少有两个存在的理由:

(1) 写语句 pd->f(100); 的人可能真的想调用 CDerived::f(char*) 函数,只是他把参数写错了。有了隐藏规则,编译器可以明确的指出错误,这对我们来说是一件好事。如果编译器将错就错,程序员很难发现这个错误,留下祸根。

(2) 假如 CDerived 类有多个基类,有时搞不清哪些基类定义了函数 f。如果没有隐藏规则,那么 pd->f(100) 可能会调用一个出乎意料的基类函数 f。尽管隐藏规则看起来不怎么有道理,但它的确能消灭这些意外。

解决办法: 如果在上面的例子中,一定要用 pd->f(100); 调用CBase::f(int),那么可以这样修改 CDerived 类:

class CDerived:public CBase
{
public:
void f(char *str) { cout<<"CDerived::f(char*)"<<" "<<str<<endl; }

void f(int x) { CBase::f(x); }
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: