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

时间:2016-01-26 14:56:47

标签: 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;
};

这里我定义了两个基类和一个从这两个继承的派生类。 main()实现如下:

int main() {

  Derived* myderived =new Derived();
  myapi* dbmodule= new myapi();
  dbmodule->start(myderived);
  dbmodule->callback();
  return 0
  }

我希望看到funk2和punk2一个接一个地被调用。然而,结果对我来说是令人震惊的。 Callback()似乎调用funk1和punk1。屏幕输出如下:

Derived constructor
funk1 function in Derived!!!
punk1 in Derived!!!

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

1 个答案:

答案 0 :(得分:5)

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

首先看一下,如图所示使用void*强制转换应该不会有问题,因为你最终会向基础投射,对吧?因此,即使在某些时候通过void*丢失了该类型的信息,它应该被重新获得?虚函数调用应该仍然有效吗?

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

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

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

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

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

相关问题