当C++多继承遇上类型转换[转]
1 由来
2 原型与问题
- #include <iostream>
- #include <hash_map>
- using namespace std;
- class I1
- {
- public:
- virtual void vf1()
- {
- cout << "I'm I1:vf1()" << endl;
- }
- };
- class I2
- {
- public:
- virtual void vf2()
- {
- cout << "I'm I2:vf2()" << endl;
- }
- };
- class C : public I1, public I2
- {
- private:
- hash_map<string, string> m_cache;
- };
- I1* CreateC()
- {
- return new C();
- }
- int main(int argc, char** argv)
- {
- I1* pI1 = CreateC();
- pI1->vf1();
- I2* pI2 = (I2*)pI1;
- pI2->vf2();
- delete pI1;
- return 0;
- }
#include <iostream>
#include <hash_map>
using namespace std; class I1
{
public:
virtual void vf1()
{
cout << "I'm I1:vf1()" << endl;
}
}; class I2
{
public:
virtual void vf2()
{
cout << "I'm I2:vf2()" << endl;
}
}; class C : public I1, public I2
{
private:
hash_map<string, string> m_cache;
}; I1* CreateC()
{
return new C();
} int main(int argc, char** argv)
{
I1* pI1 = CreateC();
pI1->vf1(); I2* pI2 = (I2*)pI1;
pI2->vf2(); delete pI1;
return 0;
}
3 分析
- int main(int argc, char** argv)
- {
- I1* pI1 = CreateC();
- pI1->vf1();
- I2* pI2 = (I2*)pI1;
- pI2->vf2();
- cout << "pI1指向的地址为:"<<std::hex << pI1 << endl;
- cout << "pI2指向的地址为:"<<std::hex << pI2 << endl;
- delete pI1;
- return 0;
- }
int main(int argc, char** argv)
{
I1* pI1 = CreateC();
pI1->vf1(); I2* pI2 = (I2*)pI1;
pI2->vf2(); cout << "pI1指向的地址为:"<<std::hex << pI1 << endl;
cout << "pI2指向的地址为:"<<std::hex << pI2 << endl;
delete pI1;
return 0;
}
执行结果为:
- #include <iostream>
- #include <hash_map>
- using namespace std;
- class I1
- {
- public:
- virtual void vf1()
- {
- cout << "I'm I1:vf1()" << endl;
- }
- };
- class I2
- {
- public:
- virtual void vf2()
- {
- cout << "I'm I2:vf2()" << endl;
- }
- virtual void vf3()
- {
- cout << "I'm I2:vf3()" << endl;
- }
- };
- class C : public I1, public I2
- {
- private:
- hash_map<string, string> m_cache;
- };
- I1* CreateC()
- {
- return new C();
- }
- int main(int argc, char** argv)
- {
- I1* pI1 = CreateC();
- pI1->vf1();
- I2* pI2 = (I2*)pI1;
- pI2->vf2();
- pI2->vf3();
- cout << "pI1指向的地址为:"<<std::hex << pI1 << endl;
- cout << "pI2指向的地址为:"<<std::hex << pI2 << endl;
- delete pI1;
- return 0;
- }
#include <iostream>
#include <hash_map>
using namespace std; class I1
{
public:
virtual void vf1()
{
cout << "I'm I1:vf1()" << endl;
}
}; class I2
{
public:
virtual void vf2()
{
cout << "I'm I2:vf2()" << endl;
}
virtual void vf3()
{
cout << "I'm I2:vf3()" << endl;
}
}; class C : public I1, public I2
{
private:
hash_map<string, string> m_cache;
}; I1* CreateC()
{
return new C();
} int main(int argc, char** argv)
{
I1* pI1 = CreateC();
pI1->vf1(); I2* pI2 = (I2*)pI1;
pI2->vf2();
pI2->vf3(); cout << "pI1指向的地址为:"<<std::hex << pI1 << endl;
cout << "pI2指向的地址为:"<<std::hex << pI2 << endl;
delete pI1;
return 0;
}
4 解决思路
- int main(int argc, char** argv)
- {
- I1* pI1 = CreateC();
- pI1->vf1();
- I2* pI2 = dynamic_cast<I2*>(pI1);
- pI2->vf2();
- delete pI1;
- return 0;
- }
int main(int argc, char** argv)
{
I1* pI1 = CreateC();
pI1->vf1(); I2* pI2 = dynamic_cast<I2*>(pI1);
pI2->vf2(); delete pI1;
return 0;
}
此时,编译和运行都如预期一样,完全正确。缺陷就是开启RTTI会影响程序性能,而且好像VC++6中无法正常工作。
- #include <iostream>
- #include <hash_map>
- using namespace std;
- class I1
- {
- public:
- virtual void vf1()
- {
- cout << "I'm I1:vf1()" << endl;
- }
- };
- class I2
- {
- public:
- virtual void vf2()
- {
- cout << "I'm I2:vf2()" << endl;
- }
- virtual void vf3()
- {
- cout << "I'm I2:vf3()" << endl;
- }
- };
- class C : public I1, public I2
- {
- private:
- hash_map<string, string> m_cache;
- };
- I1* CreateC()
- {
- return new C();
- }
- I2* QueryInterface(I1* obj)
- {
- C* pC = static_cast<C*>(obj);
- return static_cast<I2*>(pC);
- }
- I1* QueryInterface(I2* obj)
- {
- C* pC = static_cast<C*>(obj);
- return static_cast<I1*>(pC);
- }
- int main(int argc, char** argv)
- {
- I1* pI1 = CreateC();
- pI1->vf1();
- I2* pI2 = QueryInterface(pI1);
- pI2->vf2();
- delete pI1;
- return 0;
- }
#include <iostream>
#include <hash_map>
using namespace std; class I1
{
public:
virtual void vf1()
{
cout << "I'm I1:vf1()" << endl;
}
}; class I2
{
public:
virtual void vf2()
{
cout << "I'm I2:vf2()" << endl;
}
virtual void vf3()
{
cout << "I'm I2:vf3()" << endl;
}
}; class C : public I1, public I2
{
private:
hash_map<string, string> m_cache;
}; I1* CreateC()
{
return new C();
} I2* QueryInterface(I1* obj)
{
C* pC = static_cast<C*>(obj);
return static_cast<I2*>(pC);
} I1* QueryInterface(I2* obj)
{
C* pC = static_cast<C*>(obj);
return static_cast<I1*>(pC);
} int main(int argc, char** argv)
{
I1* pI1 = CreateC();
pI1->vf1(); I2* pI2 = QueryInterface(pI1);
pI2->vf2(); delete pI1;
return 0;
}
这种方式,既可以得到正确的运行结果,也不需要用户调用dynamic_cast,所以效果最好。但实现和调用都较为麻烦,使得库的使用不方便。
5 一点感想
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApplication1
- {
- class Program
- {
- static void Main(string[] args)
- {
- I1 pI1 = new C();
- pI1.vf1();
- I2 pI2 = (I2)pI1;
- pI2.vf2();
- }
- }
- interface I1
- {
- void vf1();
- }
- interface I2
- {
- void vf2();
- }
- class C : I1, I2
- {
- public void vf1()
- {
- Console.WriteLine("I'm vf1()");
- }
- public void vf2()
- {
- Console.WriteLine("I'm vf2()");
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
I1 pI1 = new C();
pI1.vf1();
I2 pI2 = (I2)pI1;
pI2.vf2();
}
} interface I1
{
void vf1();
} interface I2
{
void vf2();
} class C : I1, I2
{
public void vf1()
{
Console.WriteLine("I'm vf1()");
}
public void vf2()
{
Console.WriteLine("I'm vf2()");
}
}
}
(2)开发库的时候,对外接口以类的形式是否合适?是否还是以纯粹的C函数为接口更简洁?C++的前途....
当C++多继承遇上类型转换[转]的更多相关文章
- 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署
谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...
- MVC遇上bootstrap后的ajax表单模型验证
MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...
- 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)
邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...
- 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)
我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- 初识genymotion安装遇上的VirtualBox问题
想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...
- SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案
SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...
- 当创业遇上O2O,新一批死亡名单,看完震惊了!
当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)
当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
随机推荐
- 通过页面调用APP【H5与APP互通】
现在H5和App原生的内容原来越互通,所涉及的业务也越来越复杂和融合,所以如何互相之间方便的调用才是王道. 场景1 比如用hybrid获取地理位置和短信信息,这当然需要框架封装好,比如利用框架的bri ...
- Sphinx Search 学习 (一)
参考资料一:(中文)http://www.coreseek.cn/docs/coreseek_3.2-sphinx_0.9.9.html (官方)http://sphinxsearch.com/doc ...
- cocoapods Analyzing dependencies 问题的解决方案
pod install --verbose --no-repo-update pod update --verbose --no-repo-update 修改就ok了
- NetworkComms V3 使用Json序列化器进行网络通信
刚才在网上闲逛,偶然看到一篇文章 C#(服务器)与Java(客户端)通过Socket传递对象 网址是:http://www.cnblogs.com/iyangyuan/archive/2012/12/ ...
- iOS UIWebView 添加tap手势 和 添加button 遇到的问题
今天应产品需求,在UIWebView 上添加一个 单机手势和双击手势,再加一个UIButton,UIButton 绑定一件事情,结果遇到了点击button 的点击事件的时候,单机手势 的响应事件,被响 ...
- iOS版本更新的App提交审核流程
App的版本更新估计是在所难免的了!更新App和新的App发布有何不同了?今天我们一起来看看吧!在发布App的时候我们需要通过开发者帐号——(申请)——>发布证书(需要钥匙串对证书签名也叫加密( ...
- UIScrollView无法滚动的解决办法及UIScrollView的代理(delegate)
1•如果UIScrollView无法滚动,可能是以下原因: Ø没有设置contentSize ØscrollEnabled = NO Ø没有接收到触摸事件:userInteractionEnabled ...
- 【Python】【学习笔记】1.快速入门
1.软件安装 从官网下载相应版本的安装包,一般不大. https://www.python.org/ 安装一路默认即可 2. 参考教程:快速入门:十分钟学会Python 本文的内容介于教程(Totur ...
- 【工具】【电子设计】超屌的 fritzing 新建元件
fritzing 有多好,用了才知道,但是通常会遇到一个问题,他的元件库不一定够用,这时候就得自己做元件了,但是搜了一下网上没有相关的教程啊. 算了,去官网看英文吧.. 首先在最新版本不支持直接新建元 ...
- bzoj 3211: 花神游历各国
#include<cstdio> #include<cmath> #include<iostream> #define M 100006 using namespa ...