C++继承体系中名字遮挡问题

王朝c/c++·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

C++中派生类函数遮挡(Hide)基类中同名函数的问题是比较令人费解的,有必要详细说明一下。

看看下面一段代码:

class Base

{

public:

virtual void f(int x) {};

};

class Derived : public Base

{

public:

virtual void f(void* p) {};

};

Derived *pd = new Derived;

pd->f(10); //编译错误

对于这样一种情况,Scott Meyers这样解释(Effective C++中文第二版 第50条),Derived::f遮蔽了Base::f,即使两者的参数类型并不相同。也就是说编译器不知道有一个参数类型为int的Base::f存在。

但是下面的代码却可以编译通过:

Base *pb = new Derived;

pb->f(10);

Bjarne Stroustrup在ARM中对此的解释是:假设当你调用f时,你真正想调用的时Derived版本,但你意外地使用了错误的参数类型(本例为int)。更进一步假设Derived是继承体系中的一员,而且你并不知道Derived间接继承了某个BaseClass,后者声明有一个虚拟函数f,需要一个int参数。这种情况下你将意外调用BaseClass::f——一个你甚至并不知道它存在的函数。这种错误有可能在大型继承体系中常常发生,所以Stroustrup决定釜底抽薪(好一个釜底抽薪!)地令derived class members遮蔽同名的base class members。

再看看以下代码:

class Base

{

public:

virtual void f(int x) {};

virtual void f(char* x) {};

};

class Derived : public Base

{

public:

virtual void f(int x){};

};

Derived *pd = new Derived;

pd->f((char*)2); // 编译错误

pd->f(2); // 通过

Base *pb = new Derived;

pb->f((char*)2); // 通过

pb->f(2); // 通过

根据以上的解释,应该不难理解这样的编译结果。那么我们看看静态函数是否一样的情况。

class Base

{

public:

static void f(int x) {};

};

class Derived : public Base

{

public:

static void f(void* x) {}; //不论此定义前是否有 static,都有以下结果

};

Derived *pd = new Derived;

pd->f(2); // 编译错误

pd->f((void*)2); // 通过

Base *pb = new Derived;

pb->f(2); // 通过

pb->f((void*)2); // 错误

这样我们发现对于static函数,一样存在如上所述的遮蔽作用。C++允许派生类重新定义基类中的任何函数(private除外),这种权力是一把双刃剑,在给予程序员能力的同时也诱导他们犯错误。

class Base

{

public:

static void f(int x) {};

};

class Derived : public Base

{

public:

virtual void f(int x) {};

};

class Son : public Derived

{

public:

virtual void f(int x){};

};

Son *ps = new Son;

Derived *pd = ps;

Base *pb = pd;

ps->f(2); // 调用 Son::f

pd->f(2); // 调用 Son::f

pb->f(2); // 调用 Base::f

以上这种在开发继承层次很多的大型软件时表现出来的精神分裂症就很难找到问题根源。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航