Krcn U
Krcn U

Reputation: 421

C++ calling function results in calling another function

I`ve faced with a very interesting issue, i hope you can help me what i am doing wrong here..

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;
};

Here I have defined two base classes and one derived class inheriting from these two. main() implementation is as follows:

int main() {

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

I expect to see that funk2 and punk2 are getting called one after another. However result is shockingly new to me . Callback() seems to call funk1 and punk1. Screen output is like below:

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

Hope you can let me know what i am getting wrong here.Thanks

Upvotes: 1

Views: 402

Answers (1)

SergeyA
SergeyA

Reputation: 62583

The answers and comments do not quite go down to the bottom of it, so I will try to address this.

On the first look, using void* casts as shown should not be of a problem, because you end up casting to the base, right? So even if at some point the information of the type was lost through void*, it should be re-aquired? The virtual function calls should still work?

They would, if not for multiple inheritance. In single-inheritance scenario, correct virtual functions would be still called. But when you have multiple inheritance, you need to know the type to properly calculate offset to one of the bases.

A bit of background. Virtual functions are usually represented through so-called VTABLE - which can be thought of as a table of pointers to functions. For every specific class there is a copy of such table (per class, not per object!) which will have pointers set to corresponding member functions, defined in that class. Every object of the class has a pointer to this table (so that multiple objects of the same class all share the same table).

For single inheritance, there is only one vtable pointer and it's the first member of the class. As a result, it doesn't matter how you cast your pointer in between, as long as you cast it to correct type before calling virtual function, you will be calling the proper virtual function.

However, in case of multiple non-virtual inheritance, there is more than one ponter to vtable. You have a pointer for every parent! So when you cast to the parent, the resulting pointer would point to one of the bases - by offsetting the pointer to the object to the pointer to vtable of the class you cast to. If you first cast to void*, this crucial step is not performed, and resulting void* is simply pointing to the first vtable in your class. And even when you cast back to the proper base, there is no longer needed information to perform proper offsetting - all the compiler sees is the void*, it would have no ither information - and the pointer remains pointing to the first vtable.

As a result of all this, you end up calling virtual functions from incorrect base!

Upvotes: 5

Related Questions