当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(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
随机推荐
- C++ 在容器中存放函数指针
注意,对一般c++ 98标准编译器而言,容器泛型模板是不支持直接存放函数指针的.需要typedef将函数指针重命名. 比如,一个void返回值参数也为void的函数指针,需要 typedef void ...
- iOS开发常用代码块(2)
GCD定时器 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispa ...
- VS2010开发AutoCAD 2012 .net应用程序调试时断点不起作用
VS2010+ AutoCAD 2012开发调试过程中,发现普通的Class里面的断点是可以跟踪到的,可能是创建自定义的Form做界面是,Form1.cs中的代码断点却不管用.原因在于AutoCAD的 ...
- iOS:iOS中的多控制器管理
iOS中的控制器有三种创建方式: 1.通过storyboard创建 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@" ...
- 360浏览器兼容模式默认显示ie最高版本
之前写完代码都会放在360浏览器里跑一边,基本没啥问题,因为设置的都是极速模式,极速模式内置的是webkit内核,后来测试人员测试了兼容模式,发现会出各种问题,打开控制台一看,“我的天呐”,默认的竟然 ...
- Apache与nginx优缺点对比
1.nginx相对于Apache优点: nginx轻量级,同样起web服务,比apache占用更少的内存资源: 抗并发,nginx处理请求是异步非阻塞型的,Apache处理请求是阻塞型的,所以在处理高 ...
- redhat openshift 跳转
网址: https://openshift.redhat.com/ OpenShift免费套餐的限制是:最多15PV/s,有3个512MB内存的应用,月流量在50K以下. 可以绑米,可惜的是,需要代理 ...
- jQuery使用ajaxSubmit()提交表单示例
ajaxSubmit(obj)方法是jQuery的一个插件jquery.form.js里面的方法,所以使用此方法需要先引入这个插件.如下所示: 代码如下: <script src=" ...
- https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform
https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform
- 读取.properties配置文件
方法1 public class SSOUtils { protected static String URL_LOGIN = "/uas/service/api/login/info&q ...