C++调用函数导致调用另一个函数

Krc*_*n U 1 c++ inheritance

我面对一个非常有趣的问题,我希望你能帮助我,我在这里做错了什么..

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)

希望你能告诉我这里的错误.谢谢

Ser*_*eyA 5

答案和评论并没有完全归结到底部,所以我将尝试解决这个问题.

首先看一下,void*如图所示使用强制转换应该不会有问题,因为你最终会投射到底座上,对吗?因此,即使在某种程度上该类型的信息丢失了void*,它应该被重新获得?虚函数调用应该仍然有效吗?

如果没有多重继承,他们会.在单继承场景中,仍将调用正确的虚函数.但是当你有多个继承时,你需要知道类型来正确计算其中一个基数的偏移量.

一点背景.虚函数通常通过所谓的VTABLE表示 - 可以将其视为函数指针表.对于每个特定的类,都有一个这样的表的副本(每个,而不是每个对象!),它将指针设置为在该类中定义的相应成员函数.该类的每个对象都有一个指向该表的指针(以便同一个类的多个对象共享同一个表).

对于单继承,只有一个vtable指针,它是该类的第一个成员.因此,如何在两者之间转换指针并不重要,只要在调用虚函数之前将其转换为正确的类型,就会调用正确的虚函数.

但是,在多个非虚拟继承的情况下,vtable有多个ponter.每个父母都有一个指针!因此,当您转换为父级时,结果指针将指向其中一个基础 - 通过将指向对象的指针偏移到指向您投射到的类的vtable的指针.如果你第一次投射void*,这个关键步骤不会执行,结果void*只是指向你班上的第一个vtable.即使你回到适当的基础,也不再需要信息来执行适当的偏移 - 所有编译器都看到void*,它没有其他信息 - 并且指针仍然指向第一个vtable.

由于这一切,你最终会从错误的基础调用虚函数!