当C++多继承遇上类型转换
1 由来
客户用陈旧的VC++6.0进行项目开发,有一块功能需要我来实现。让一个早就习惯了VS2013的人去使用C++支持不太好的VC6去做开发实在是非常不爽,于是另辟蹊径,打算使用VC++2013开发编译出DLL,供VC6下调用即可。使用C++开发DLL的基本原则是减少暴露和接口简单化,最常用的方式就是使用纯虚类导出接口。另一种就是使用C++实现,但是导出时只导出C函数。处于使用的便利性考虑,采用了第一种方式。
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;
}
采用基于接口的设计方法,对外只暴露接口类I1和I2,对于实际的实现类C则对外隐藏。客户在使用的时候,只需要调用CreateC()就可以产生C类型的对象,而不必知道C的实现细节。然后通过不同的接口调用不同方面的功能。看起来一切还可以,但实际运行却是有问题的,上述代码执行结果如下:
第二行的输出对应pI2->vf2(),显然结果是错误的,调用者的本意是调用I2::vf2(),实际却调用了I1::vf1()。随后我发现这个问题其实在论坛上也有人提出过,也有不少人给出了答案,但是感觉解释的不够明确和详细,所以决定亲自一探究竟。