守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 1811|回复: 0

[C++] 多重继承中的动态绑定

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52691
    钢镚
    1422

    开源英雄守望者

    发表于 2015-1-16 13:43:22 | 显示全部楼层 |阅读模式
    C++是一种自由度非常高的语言,特别是面向对象中的动态绑定特性,正确使用这种特性会你写代码非常舒畅.但是错误的使用有时候也很致命.
    今天在编写战斗逻辑层代码的时候在释放技能回调的地方使用了C++的多重继承,在一个继承了几个回调基类(技能释放完毕回调,移动完毕回调等)的派生类里面出现了无法绑定到正确的基类对象的问题.仔细分析后发现是由于在第一层类型转换的时候已经把指针转换为void*,然后在最后一层调用无法正确转换.下面把问题重现:
    假设我们的基类是:CInheritFirst,CInheritSecond,派生类是CInheritMain
    如下:

    1. /*  
    2. * InheritMain.h
    3. *
    4. * Created by Rect on 2014-5-30 16:11.
    5. * Copyright (c) 2014年 shadowkong.com. All rights reserved.
    6. */

    7. struct CInheritFirst
    8. {
    9.     virtual void onFirstCall() = 0;

    10.     virtual void onSecondCall() = 0;
    11. };

    12. struct CInheritSecond
    13. {
    14.     virtual void onThirdCall() = 0;
    15. };

    16. class CInheritMain:
    17.     public CInheritFirst,public CInheritSecond
    18. {
    19. public:
    20.     CInheritMain(void);
    21.     ~CInheritMain(void);

    22.     virtual void onFirstCall();
    23.     virtual void onSecondCall();
    24.     virtual void onThirdCall();
    25. };
    复制代码
    然后在另外一个类中使用传入的指针回调CInheritSecondonThirdCall函数:
    1. /*  
    2. * InIeritTest.h
    3. *
    4. * Created by Rect on 2014-5-30 16:27.
    5. * Copyright (c) 2014年 shadowkong.com. All rights reserved.
    6. */
    7. #include
    8. #include "InheritMain.h"
    9. class CInIeritTest
    10. {
    11. public:
    12.     CInIeritTest(void){};
    13.     ~CInIeritTest(void){};
    14.     void test(void* pCSecind = NULL)
    15.     {
    16.         CInheritSecond* pTest = (CInheritSecond*)pCSecind;
    17.         printf("CInIeritTest::test begin\n");
    18.         pTest->onThirdCall();
    19.         printf("CInIeritTest::test end\n");
    20.     };
    21. };
    复制代码
    main中如下调用:
    两次调用test发现会发生不一样的效果:pTest->test((CInheritSecond*)pMain) 正确了onThirdCall;pTest->test(pMain)确调用了onFirstCall也就是说:
    • 在第一次调用的时候函数指针动态绑定到了CInheritSecond
    • 在第二次调用的时候函数指针动态绑定到了CInheritFirst
    为什么会发生这种事情呢?由于我们传入的指针默认转换为void*
    1. pTest->test((CInheritSecond*)pMain)
    复制代码
    调用pTest->test((CInheritSecond*)pMain)的时候 指针先绑定到CInheritSecond在转换到void* ,这样在test函数中函数指针无论绑定到那个类 其实都只有CInheritSecond了.其实转换成任意一个其他类,在调用函数的时候 都会搜索函数表.由于CInheritSecond只有一个函数 所以无论指针怎么转换 他都只有一个函数可以调用.
    1. pTest->test(pMain)
    复制代码
    调用pTest->test(pMain)其实传入的是CInheritMain*,这样在使用的时候 指针转换 无论怎么转换 其实都是CInheritMain*,无论转换到那个基类,调用那个函数,都会调用到CInheritMain类来.这个类有三个函数,对象函数表里也只有三个函数指针.可能没有实际测试过代码 看起来有点模糊,总结一句话 就是:
    对于传入任何A类型指针,只要形参是void*,那在函数内部无论转换成B,C,D,E,F还是G,那这个指针实际上都是A.代码Sample托管在我的github

    本文来自:http://shadowkong.com/archives/1747


    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2024-4-19 02:21 , Processed in 0.061219 second(s), 35 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

    快速回复 返回顶部 返回列表