问题重现
定义了两个接口IA IB
使用一个类继承了这两个接口,实现了他们的纯虚函数
class CC:public IA,public IB{
public:
void funA(){
cout<<"IA func"<<endl;
}
void funB(){
cout<<"IB func"<<endl;
}
};
定义一个start函数,参数为void*,利用虚函数的多态特性,在函数内通过类型转换分别调用接口IA和IB的虚函数
在主函数里,定义一个子类,传入start函数,期望的是输出接口IA和IB各自的虚函数
实际的输出却全部调用了IA的函数funA
g++ a.cpp
a
IA func
IA func
问题分析
多继承的情况下,子类将有多个虚函数表,start函数内,ia指向了接口IA的虚函数表,而ib也指向了IA的虚函数表,导致ib调用了IA的虚函数。IA是子类第一个继承的接口,也就是说他们都指向了第一个继承的父类的虚函数表
如果为程序再添加函数
main函数改为
此时就会出现想要的结果,成功的调用了IA和IB接口内的虚函数
g++ a.cpp
a
IA func
IB func
尝试下面的代码
int main(){
void *cc = new CC();
IB *ib = (IB*)cc;
ib->funB();
IB *ibb = (CC*)cc;
ibb->funB();
return 0;
}
输出
g++ a.cpp
a
IA func
IB func
可以看到第一个IB指针调用了接口IA的函数,而第二个IB指针是正确的调用了它的函数
当子类为多继承接口,并且指针类型为void*时,进行强制类型转换为父类,就会出现虚函数表指向的错误,指向第一个继承的接口类的虚函数表,只有知道子类的类型再进行转换为父类,才可以指向正确的虚函数表。
解决办法
解决办法是使用dynamic_cast进行类型转换。dynamic_cast是将一个基类对象指针(或引用)转换到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理。
将子类指针先转换成继承的第一个接口类的指针,然后使用dynamic_cast转化为所需接口的指针类型
尝试下面的都是错误的
void *cc = new CC();
IB *ibb = dynamic_cast<IB*>((IB*)cc);//依旧调用IA的虚函数
IB *ibb = dynamic_cast<IB*>(cc);//编译错误,dynamic_cast不能使用void*类型参数
ibb->funB();
修改后的start函数代码
void start(void *arg){
IA *ia = (IA*)arg;
ia->funA();
IB *ib = dynamic_cast<IB*>((IA*)arg);
ib->funB();
}
main函数
正确的输出
g++ a.cpp
a
IA func
IB func
除此之外