用户操作
[即时聊天] [发私信] [加为好友]
邓际锋ID:soloist
84493次访问,排名1137好友1人,关注者2
soloist的文章
原创 39 篇
翻译 0 篇
转载 0 篇
评论 189 篇
soloist的公告
欢迎吹毛求疵,感谢您对任何错误的指正,包括技术的、语法的、用词的、标点的、典故的、引用资料的……
最近评论
qingbai:lua绝对是个好东西。但国内除了java就是.net,其他东西没法活。因为程序员得工作,得吃饭。国内有哪家公司用lua?唉没办法呀。国外是一片繁荣,“百家争鸣”,国内是“青一色”的java和.net!无奈!
zhangyilan:尽管没有在实际代码的编写中碰到这个问题,不过也先学习一下,免得出现问题了搞出清楚情况。
ddrmsdos:这篇文章写的太好了,分析的非常仔细,以前常常碰到这类问题,终于解了我多年的心头之患......
ollydbg23:楼主的这篇文章写的非常好啊!
我看了以后,还是挺有收获感的,多谢多谢!
我也是对汇编,c++的比较感兴趣,有空可以交流一下!
w2001:写得很好
文章分类
收藏
    相册
    好博链接
    C++罗浮宫
    cpper
    fixopen
    fmddlmyy
    neoragex2002
    whinah
    云风
    梦想风暴
    沉思者
    许式伟
    负暄琐话
    辣子鸡丁
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 C++继承体系中名字遮挡问题收藏

    新一篇: 模板参数推导 | 旧一篇: 关于内存分配与释放的试验

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

    发表于 @ 2004年10月25日 20:29:00|评论(loading...)|编辑

    新一篇: 模板参数推导 | 旧一篇: 关于内存分配与释放的试验

    评论

    #leealbert 发表于2004-11-03 18:40:00  IP: 222.28.127.*
    这可以归结为类的继承中虚函数的定义问题.当派生类的相应函数只是名称相同而函数原形(函数名,返回类型,参数个数,参数类型的顺序)不是完全相同的话,即使在函数前加Virtual,还是会被系统认为是一般的函数重载,而不是虚函数.比如第一个例子:
    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); //编译错误,此处调用的是f(void* p)
    Base *pb = new Derived;
    pb->f(10);//此处调用的是f(int x)
    由于Derived中的f()的函数原形与Base中的不完全一样,所以被认为是一般的函数重载.当用派生类指针调用f()的时候,系统理解为调用的是在派生类中被从新定义过的f(void* p),形参与实参不一致,故编译错误;而当用基类指针pb调用f()的时候,调用的是基类中的f(int x),,故编译可以通过.
    对于第三个例子,
    由于Derived::f和son::f函数原形相同,所以是虚函数
    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


    #本文作者 发表于2004-11-04 18:34:00  IP: 218.78.224.*
    没错,有的时候重定义(override)和重载(overload)的细微区别就是混乱的根源。C++强制重定义的的虚拟函数的参数在类型上一定要与父类的完全相同,否则就视为重载。而对于返回值则相对宽松一点,假如父类虚拟函数返回值为A*或A&(A为某基类),则子类中它的重定义版本的返回值可为B*或B&(B为A的派生类),这种情况称为返回值类型的协变(covariant)。
    #null 发表于2006-01-02 21:29:00  IP: 61.183.207.*
    对于private virtual function,derived class是可以重载base class的,如:
    class base {
    public:
    void print( void ) { doPrint(); }
    private:
    virtual void doPrint( void ) { std::cout << "base class" << std::endl; }
    };

    class derive {
    private:
    virtual void doPrint( void ) { std::cout << "derive class" << std::endl; }
    };

    base *pb = new derive();
    pb->print();
    输出结果为:derive class
    这种情况下,private virtual function是可以重载的
    #null 发表于2006-01-02 21:30:00  IP: 61.183.207.*
    忘了继承base了
    class derive : public base {
    ......
    };
    #soloist 发表于2006-01-06 15:45:00  IP: 218.78.226.*
    to null:

    你举的例子是可行的。我要检讨一下自己这方面的认识了。另外更正一下你的说法,你的例子说的是override,一般译成覆写、重写,我喜欢称之为重定义,而重载一般指的是overload。
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © soloist