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

原创 2004年10月25日 20:29:00

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

3.11 parallel inheritance hierarchies (平行继承体系)

如果为某个类增加一个子类,必须也为另一个类相应增加一个子类。如果发现某个继承体系的类名称前缀和另一个继承体系的类名称前缀完全相同,便是这种坏味道。 策略:让一个继承体系的实例引用另一个继承体系的实例...
  • ptn3900
  • ptn3900
  • 2011年10月19日 09:20
  • 726

c++标准异常类的继承实现

出处来自百度。查来学习之用 // AbnomalTest.cpp : 定义控制台应用程序的入口点。 #include "StdAfx.h" #include using namespace ...
  • ghevinn
  • ghevinn
  • 2012年10月30日 14:30
  • 1491

c++继承体系

c++继承体系
  • kaclok
  • kaclok
  • 2015年07月06日 12:35
  • 201

java中的异常的继承体系

异常的继承体系 Throwable是java中异常和错误的顶层父类,只有继承Throwable类的子类才能够通过throws语句或者java虚拟机抛出去 Throwable的常用方法: ...
  • AllTheWayForward
  • AllTheWayForward
  • 2017年02月24日 00:39
  • 1031

JAVA继承体系

JAVA继承体系   一·类(class)的概 类:对实体的共同点(属性,行为)的集合。 创建一个类:public class test{ } 对象:实体(生活中看的到的摸的着的东西)。 ...
  • qq2687695102
  • qq2687695102
  • 2017年01月03日 19:28
  • 101

C++对象模型——继承体系下的对象构造(第五章)

5.2 继承体系下的对象构造 当定义一个object如下: T object; 时,实际上会发生什么事情呢?如果T有一个constructor(不论是由user提供或是由编译器合成),它会被调用.这很...
  • yiranant
  • yiranant
  • 2015年08月13日 20:10
  • 637

Spring IOC-BeanFactory的继承体系结构

本文主要介绍BeanFactory以及它的各种继承层级的接口、抽象类及实现类,因为内容很多,所以这里不介绍ApplicationContext继承体系下的类(虽然ApplicationContext本...
  • chenzitaojay
  • chenzitaojay
  • 2015年07月01日 22:41
  • 1500

unity3d 角色头顶信息3D&2D遮挡解决方案(一)

先上效果图,只凭文字描述,脑补应该有些困难- -       如图:有三个角色(我们暂且从左到右叫它们A、B、C),一个2D UI(中间动作选择的框框),一个cube(右边的方块)    ...
  • Carl180
  • Carl180
  • 2015年02月01日 23:18
  • 1024

关于NGUI中UI遮挡特效问题

做到了一个振动试验,用线表示,但是背景必须是不透明的,这样就发生了UI遮挡线的问题,经过查找资料以及自己试验,找到了一个解决办法,将UIPanel中的“rp”变量改到3000以下就可以了。...
  • n_moling
  • n_moling
  • 2017年08月19日 10:33
  • 113

Java集合详解系列----Java集合继承体系详解

Java的集合类是一种特别有用的工具,它可以用于存储数量不等的多个对象,并可以实现常用的数据结构,如栈、队列等。Java集合还可以用于板寸具有映射关系的关联数组。 java集合就像是一个容器,我们可...
  • snow_7
  • snow_7
  • 2016年06月30日 16:03
  • 2752
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++继承体系中名字遮挡问题
举报原因:
原因补充:

(最多只允许输入30个字)