- 积分
- 136188
- 注册时间
- 2014-12-27
- 最后登录
- 2024-4-10
- 在线时间
- 603 小时
- 威望
- 562
- 贡献
- 29
- 金币
- 52691
- 钢镚
- 1422
- 交易凭证
- 1
- 分享
- 0
- 精华
- 33
- 帖子
- 2094
- 主题
- 1742
TA的每日心情 | 擦汗 2018-4-10 15:18 |
---|
签到天数: 447 天 [LV.9]以坛为家II
超级版主
- 威望
- 562
- 贡献
- 29
- 金币
- 52691
- 钢镚
- 1422
|
C++是一种自由度非常高的语言,特别是面向对象中的动态绑定特性,正确使用这种特性会你写代码非常舒畅.但是错误的使用有时候也很致命.
今天在编写战斗逻辑层代码的时候在释放技能回调的地方使用了C++的多重继承,在一个继承了几个回调基类(技能释放完毕回调,移动完毕回调等)的派生类里面出现了无法绑定到正确的基类对象的问题.仔细分析后发现是由于在第一层类型转换的时候已经把指针转换为void*,然后在最后一层调用无法正确转换.下面把问题重现:
假设我们的基类是:CInheritFirst,CInheritSecond,派生类是CInheritMain
如下:
- /*
- * InheritMain.h
- *
- * Created by Rect on 2014-5-30 16:11.
- * Copyright (c) 2014年 shadowkong.com. All rights reserved.
- */
- struct CInheritFirst
- {
- virtual void onFirstCall() = 0;
- virtual void onSecondCall() = 0;
- };
- struct CInheritSecond
- {
- virtual void onThirdCall() = 0;
- };
- class CInheritMain:
- public CInheritFirst,public CInheritSecond
- {
- public:
- CInheritMain(void);
- ~CInheritMain(void);
- virtual void onFirstCall();
- virtual void onSecondCall();
- virtual void onThirdCall();
- };
复制代码 然后在另外一个类中使用传入的指针回调CInheritSecond的onThirdCall函数:
- /*
- * InIeritTest.h
- *
- * Created by Rect on 2014-5-30 16:27.
- * Copyright (c) 2014年 shadowkong.com. All rights reserved.
- */
- #include
- #include "InheritMain.h"
- class CInIeritTest
- {
- public:
- CInIeritTest(void){};
- ~CInIeritTest(void){};
- void test(void* pCSecind = NULL)
- {
- CInheritSecond* pTest = (CInheritSecond*)pCSecind;
- printf("CInIeritTest::test begin\n");
- pTest->onThirdCall();
- printf("CInIeritTest::test end\n");
- };
- };
复制代码 在main中如下调用:
两次调用test发现会发生不一样的效果:pTest->test((CInheritSecond*)pMain) 正确了onThirdCall;pTest->test(pMain)确调用了onFirstCall也就是说:- 在第一次调用的时候函数指针动态绑定到了CInheritSecond
- 在第二次调用的时候函数指针动态绑定到了CInheritFirst
为什么会发生这种事情呢?由于我们传入的指针默认转换为void*- pTest->test((CInheritSecond*)pMain)
复制代码 调用pTest->test((CInheritSecond*)pMain)的时候 指针先绑定到CInheritSecond在转换到void* ,这样在test函数中函数指针无论绑定到那个类 其实都只有CInheritSecond了.其实转换成任意一个其他类,在调用函数的时候 都会搜索函数表.由于CInheritSecond只有一个函数 所以无论指针怎么转换 他都只有一个函数可以调用.调用pTest->test(pMain)其实传入的是CInheritMain*,这样在使用的时候 指针转换 无论怎么转换 其实都是CInheritMain*,无论转换到那个基类,调用那个函数,都会调用到CInheritMain类来.这个类有三个函数,对象函数表里也只有三个函数指针.可能没有实际测试过代码 看起来有点模糊,总结一句话 就是:
对于传入任何A类型指针,只要形参是void*,那在函数内部无论转换成B,C,D,E,F还是G,那这个指针实际上都是A.代码Sample托管在我的github
本文来自:http://shadowkong.com/archives/1747
|
|