当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(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
随机推荐
- PHP之OOP要点摘要
类和对象: 类是生成对象的模板,对象是活动组件; 面向对象编程实际操作都是通过类的实例(而不是类本身)完成的: 访问控制(public.protected.private):(1) ...
- Jquery mobile 新手问题总汇
1页面缩放显示问题 问题描述: 页面似乎被缩小了,屏幕太宽了. 解决办法: 在head标签内加入: <meta name="viewport" content="w ...
- 数组中的toString,toLocalString,valueOf方法有什么区别
1. 2.简单来说,tostring就是用字符串来代替对象.tolocalstring就是根据不同的语言环境吧对象转成字符串,实际上totolocalstring是有缺省参数的,如tolocalstr ...
- ios新特性(泛型)
协变 子类转父类 逆变父类给子类赋值
- 总结js中数据类型的bool值及其比较
首先需要知道的是,js中有6个值为false,分别是: 0, '', null, undefined, NaN 和 false, 其他(包括{}, [], Infinity)为true. 可以使用Bo ...
- [转载]再来重新认识JavaEE完整体系架构
移步: http://www.jizhuomi.com/software/644.html
- 【编辑器】【Sublime Text】使用笔记
1.安装 官网下载即可 2.插件 sublime-text - Sublime Text 怎么高亮 Markdown 的文件语法 设置Sublime为VIM模式 如何在sublime 里面设置 ver ...
- 关于Xcode6创建的工程在Xcode5打开
Xcode6创建的工程在Xcode5打开- 4.0只显示3.5大小的问题 只需要在工程里添加Default-568h@2x.png,即可以解决
- callback 转换到 promise
最近项目迭代,从express到koa,面对callback,想偷懒,就想到了Proxy对象 new Proxy(docker,{ get : function (obj,name) { return ...
- AnyCAD.NET C#开发CAD软件实践(一)
免费的AnyCAD.NET发布了!俺喜欢的C#有了大展前途的机会了. 打算用这个框架搭建一套实用的CAD系统,目标是能买出去10套以上. 先看看AnyCAD.NET的自我介绍. http://www. ...