中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > 综合其它
避免覆盖通过继承得到的名字(1)
作者:佚名 时间:2007-09-24 16:33 出处:中国IT实验室 责编:月夜寒箫
              摘要:避免覆盖通过继承得到的名字(1)

莎士比亚有一个关于名字的说法。“What’s in a name?”他问道,“A rose by any other name would smell as sweet.”(语出《罗密欧与朱丽叶》第二幕第二场,朱生豪先生译为:“姓名本来是没有意义的;我们叫做玫瑰的这一种花,要是换了个名字,他的香味还是同样的芬芳。”梁实秋先生译为:“姓算什么?我们所谓有玫瑰,换个名字,还是一样的香。”——译者注)。莎翁也写过“he that filches from me my good name ... makes me poor indeed.”(语出《奥塞罗》第三幕第三场,朱生豪先生译为:“可是谁偷去了我的名誉,那么他虽然并不因此而富足,我却因为失去它而成为赤贫了。”梁实秋先生译为:“但是他若夺去我的名誉,于他不见有利,对我却是一件损失哩。”——译者注)。好吧!在C++中,我们该用哪种态度对待通过继承得到的名字呢?

事情的实质与继承没什么关系。它与作用域有关。我们都知道它在代码中是这样的, 

            

int x; // global variable 

void someFunc()

{

double x; // local variable

std::cin >> x; // read a new value for local x

}

读入x的语句指涉local变量x,而不是global变量x,因为内层作用域的名字覆盖(“遮蔽”)外层作用域的名字。我们可以像这样形象地表示作用域的状况:

当编译器在someFunc的作用域中遇到名字x时,他们巡视local作用域看看是否有什么东西叫这个名字。因为那里有,它们就不再检查其它作用域。在此例中,someFunc的x类型为double,而global x类型为int,但这不要紧。C++的name-hiding规则仅仅是覆盖那个名字。而相对应的名字的类型是否相同是无关紧要的。在此例中,一个名为x的double覆盖了一个名为x的int。

加入inheritance以后。我们知道当我们在一个derived class member function内指涉位于base class内的一件东西(例如,一个member function,一个typedef,或者一个data member)时,编译器能够找到我们指涉的东西是因为derived classes继承到声明于base classes中的东西。实际中的运作方法是将derived class的作用域嵌套在base class作用域之中。例如:

            

class Base {

private:

 int x;

public:

 virtual void mf1() = 0;

 virtual void mf2();

 void mf3();

 ...

};

class Derived: public Base {

 public:

virtual void mf1();

void mf4();

...

};

本例中包含的既有public名字也有private名字,既有data members也有member functions。member functions既有pure virtual的,也有simple (impure) virtual的,还有non-virtual的。那是为了强调我们谈论的事情是关于名字的。例子中还可以包括其它类型的名字,例如,enums,nested classes,和typedefs。在这里的讨论中唯一重要的事情是“它们是名字”。与它们是什么东西的名字毫不相关。这个示例中使用了single inheritance,但是一旦你理解了在single inheritance下会发生什么,C++在multiple inheritance下的行为就很容易预见了。

假设mf4在derived class中被实现,其中一部分,如下:

            

void Derived::mf4()

{

...

mf2();

...

}

当编译器看到这里对名字mf2的使用,它就必须断定它指涉什么。它通过搜索名为mf2的某物的定义的作用域来做这件事。首先它在local作用域中搜索(也就是mf4的作用域),但是它没有找到被称为mf2的任何东西的声明。然后它搜索它的包含作用域,也就是class Derived的作用域。它依然没有找到叫做mf2的任何东西,所以它上移到它的上一层包含作用域,也就是base class的作用域。在那里它找到了名为mf2的东西,所以搜索停止。如果在Base中没有mf2,搜索还会继续,首先是包含Base的namespace(s)(如果有的话),最后是global作用域。

我刚刚描述的过程虽然是正确的,但它还不是一个关于C++中名字如何被找到的完整的描述。无论如何,我们的目的不是为了充分了解关于写一个编译器时的名字搜索问题。而是为了充分了解如何避免令人吃惊的意外,而对于这个任务,我们已经有了大量的信息。

再次考虑前面的示例,而且这一次我们overload mf1和mf3,并且为Derived增加一个mf3的版本。(Derived对mf3——一个通过继承得到的non-virtual function——的重载,使得这个设计立即变得可疑,但是出于对inheritance之下名字可见性问题的关心,我们就装作没看见。)

            

class Base {

private:

 int x;

public:

 virtual void mf1() = 0;

 virtual void mf1(int);

 virtual void mf2();

 void mf3();

 void mf3(double);

 ...

};

class Derived: public Base {

public:

 virtual void mf1();

 void mf3();

 void mf4();

 ...

};

以上代码导致的行为会使每一个第一次遇到它的C++程序员吃惊。基于作用域的名字覆盖规则(scope-based name hiding rule)不会有什么变化,所以base class中的所有名为mf1和mf3的函数被derived class中的名为mf1和mf3的函数覆盖。从名字搜索的观点看,Base::mf1和Base::mf3不再被Derived继承!

            

Derived d;

int x;

...

d.mf1(); // fine, calls Derived::mf1

d.mf1(x); // error! Derived::mf1 hides Base::mf1

d.mf2(); // fine, calls Base::mf2

d.mf3(); // fine, calls Derived::mf3

d.mf3(x); // error! Derived::mf3 hides Base::mf3

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有