C++在构造函数中调用成员函数,实例化子类,输出结果有些出乎意料 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sbabybird
V2EX    C

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

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

    试验代码如下

    class CHello { public: CHello() { this.SayHello(); } virtual ~CHello(); virtual void SayHello() { printf("hello"); } }; class CHelloA : public CHello { publi: 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   div class="badges">   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
    7wN5407klUw768m0
        18
    7wN5407klUw768m0  
       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     Solana     936 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:52 PVG 05:52 LAX 13:52 JFK 16:52
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86