我面对一个非常有趣的问题,我希望你能帮助我,我在这里做错了什么..
class abstract1
{
public:
virtual ~ abstract1(){};
virtual void funk1()=0;
virtual void punk1()=0;
};
class abstract2
{
public:
virtual ~ abstract2(){};
virtual void funk2()=0;
virtual void punk2()=0;
};
class Derived: public abstract1,
public abstract2
{
public:
Derived(){ cout<<"Derived constructor"<<endl;};
~Derived() {cout <<"Derived destructor" <<endl;};
void funk1(){
cout<<"funk1 function in Derived!!!"<<endl;
};
void punk1(){
cout<<"punk1 in Derived!!!"<<endl;
};
void funk2(){
cout<<"funk2 function in Derived!!!"<<endl;
};
void punk2(){
cout<<"punk2 in Derived!!!"<<endl;
};
};
class myapi{
public:
void start(void *_drved){
drved=(abstract2*)_drved;
};
void callback(){
drved->funk2();
drved->punk2();
}
protected:
abstract2* drs;
};
Run Code Online (Sandbox Code Playgroud)
这里我定义了两个基类和一个从这两个继承的派生类.main()实现如下:
int main() {
Derived* myderived =new Derived();
myapi* dbmodule= new myapi();
dbmodule->start(myderived);
dbmodule->callback();
return 0
}
Run Code Online (Sandbox Code Playgroud)
我希望看到funk2和punk2一个接一个地被调用.然而,结果对我来说是令人震惊的.Callback()似乎调用funk1和punk1.屏幕输出如下:
Derived constructor
funk1 function in Derived!!!
punk1 in Derived!!!
Run Code Online (Sandbox Code Playgroud)
希望你能告诉我这里的错误.谢谢
答案和评论并没有完全归结到底部,所以我将尝试解决这个问题.
首先看一下,void*
如图所示使用强制转换应该不会有问题,因为你最终会投射到底座上,对吗?因此,即使在某种程度上该类型的信息丢失了void*
,它应该被重新获得?虚函数调用应该仍然有效吗?
如果没有多重继承,他们会.在单继承场景中,仍将调用正确的虚函数.但是当你有多个继承时,你需要知道类型来正确计算其中一个基数的偏移量.
一点背景.虚函数通常通过所谓的VTABLE表示 - 可以将其视为函数指针表.对于每个特定的类,都有一个这样的表的副本(每个类,而不是每个对象!),它将指针设置为在该类中定义的相应成员函数.该类的每个对象都有一个指向该表的指针(以便同一个类的多个对象共享同一个表).
对于单继承,只有一个vtable指针,它是该类的第一个成员.因此,如何在两者之间转换指针并不重要,只要在调用虚函数之前将其转换为正确的类型,就会调用正确的虚函数.
但是,在多个非虚拟继承的情况下,vtable有多个ponter.每个父母都有一个指针!因此,当您转换为父级时,结果指针将指向其中一个基础 - 通过将指向对象的指针偏移到指向您投射到的类的vtable的指针.如果你第一次投射void*
,这个关键步骤不会执行,结果void*
只是指向你班上的第一个vtable.即使你回到适当的基础,也不再需要信息来执行适当的偏移 - 所有编译器都看到void*
,它没有其他信息 - 并且指针仍然指向第一个vtable.
由于这一切,你最终会从错误的基础调用虚函数!
归档时间: |
|
查看次数: |
118 次 |
最近记录: |