V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Sponsored by
LinkedIn
2000 个不用坐班的远程好工作在召唤你 · 弹性上班不打卡,工作和生活都能拥有
2000 个不用坐班的全球远程工作,帮助 V2EX 的小伙伴开启全新的工作方式。
Promoted by LinkedIn
sbabybird
V2EX  ›  C

C++在构造函数中调用成员函数,实例化子类,输出结果有些出乎意料

  •  
  •   sbabybird · 2017-05-03 13:25:10 +08:00 · 2040 次点击
    这是一个创建于 1971 天前的主题,其中的信息可能已经有所发展或是发生改变。

    试验代码如下

    class CHello {
     public:
      CHello()
      {
        this.SayHello();
      }
      virtual ~CHello();
      virtual void SayHello()
      {
        printf("hello");
      }
    };
    
    class CHelloA : public CHello {
     public:
      CHelloA();
      ~CHelloA();
      void SayHello() 
      {
        printf("hello a");
      }
    };
    
    void main() 
    {
      CHelloA a;
    }
    

    猜猜输出什么?

    第 1 条附言  ·  2017-05-03 15:01:08 +08:00
    感谢大家的回复哈,尤其是 @nyanyh 提供的链接里解释的已经很清楚了,而且该文章还提供了额外的解决方案,非常不错。
    22 条回复    2017-06-06 10:02:16 +08:00
    sbabybird
        1
    sbabybird  
    OP
       2017-05-03 13:26:32 +08:00
    同样的思路,在 java 和 python 下输出是正常的,即子类的 SayHell 被调用。
    sbabybird
        2
    sbabybird  
    OP
       2017-05-03 13:29:40 +08:00
    在 vs2015 下编译的,输出显示调用的是父类的 SayHello。
    vingz
        4
    vingz  
       2017-05-03 13:32:41 +08:00
    Hello?
    limhiaoing
        5
    limhiaoing  
       2017-05-03 13:32:50 +08:00 via iPhone
    这代码能编译通过?
    wevsty
        6
    wevsty  
       2017-05-03 13:34:41 +08:00
    1、楼主的代码编译都过不了
    this 是指针,指针类型不能用.来调用
    CHelloA,~CHelloA,~CHello 都只有声明没有定义,link 的时候会 error 的
    2、如果正确修改代码
    那么最后应该是输出 hello 而不是 hello a
    solaya
        7
    solaya  
       2017-05-03 13:36:15 +08:00
    这代码 你跑过???去看看 effective c++
    wangxn
        8
    wangxn  
       2017-05-03 13:38:25 +08:00
    不要在构造函数和析构函数中调用虚函数,不是一个常识吗?楼主真是大惊小怪啊……
    vingz
        9
    vingz  
       2017-05-03 13:40:24 +08:00   ❤️ 1
    java 下,如果 sayHello 是 private 权限,父类的函数被调用,如果是其他权限(测试了 default,protected )子类的函数被调用。
    sbabybird
        10
    sbabybird  
    OP
       2017-05-03 13:43:45 +08:00
    不好意思,那个点写错了,应该是 this->SayHello();我是凭记忆打的,确实在 vs 下运行过。 @solaya
    wangxn
        11
    wangxn  
       2017-05-03 13:43:52 +08:00   ❤️ 1
    Python 之所以能在构造函数中调用到子类中的同名函数,原因在于 Python 压根没有虚函数这个概念,所谓调用只是 self 对象在它自己的 __dict__ 中进行名字查找而已。
    sbabybird
        12
    sbabybird  
    OP
       2017-05-03 13:44:46 +08:00
    @wangxn 只是想探讨一下原因,以及跟其他语言的不同
    sbabybird
        13
    sbabybird  
    OP
       2017-05-03 13:45:30 +08:00
    @wevsty 是的确实输出的是 hello
    limhiaoing
        14
    limhiaoing  
       2017-05-03 13:48:47 +08:00 via iPhone
    @sbabybird
    想探讨原因就不应该用这种标题!
    wevsty
        15
    wevsty  
       2017-05-03 13:57:23 +08:00   ❤️ 2
    @sbabybird
    对 C++来说 virtual 函数是在类对象里面有虚表来确定执行哪个函数的,但是继承过来的对象不修改基类中的虚表,而是附加新的。
    继承并不是单纯的按照基类复制成一个新的类,这里是依赖关系所以仍然会保持基类里原有的行为,在基类中实现构造的时候就确定下来的行为是不会改变的。
    sbabybird
        16
    sbabybird  
    OP
       2017-05-03 13:58:53 +08:00
    @limhiaoing 抱歉了哈,确实有些随意了,感谢指正
    huyan3280
        17
    huyan3280  
       2017-05-03 14:43:15 +08:00
    hello
    Taojun0714
        18
    Taojun0714  
       2017-05-03 16:08:19 +08:00
    去看《深度探索 C++对象模型》
    Pyjamas
        19
    Pyjamas  
       2017-05-03 16:09:15 +08:00
    上面+1
    geelaw
        20
    geelaw  
       2017-05-03 16:11:36 +08:00 via iPhone
    对象的身份(具体度)是逐渐升级的。

    这也是为什么会有“调用过了纯虚函数”这种错误,在基类的构造函数里面调用纯虚函数会失败。

    析构的时候对象身份逐渐降级。
    visionsmile
        21
    visionsmile  
       2017-05-10 23:46:37 +08:00 via Android
    楼主了解下 C++类的构造顺序就明白了。
    Frost
        22
    Frost  
       2017-06-06 10:02:16 +08:00
    effective C++里面提到过,同样的状况会出现在基类引用或指针调用基类虚函数的默认参数里,它只会认基类那个虚函数的默认参数。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2819 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 13:33 · PVG 21:33 · LAX 06:33 · JFK 09:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.