views:

101

answers:

3

I read an article on virtual table in Wikipedia.

class B1
{
public:
  void f0() {}
  virtual void f1() {}
  int int_in_b1;
};

class B2
{
public:
  virtual void f2() {}
  int int_in_b2;
};

used to derive the following class:

class D : public B1, public B2
{
public:
  void d() {}
  void f2() {}  // override B2::f2()
  int int_in_d;
};

After reading it I couldn't help but wonder how non virtual member functions are implemented in C++. Is there a separate table like the v-table in which all the function addresses are stored? If yes, what is this table called and what happens to it during inheritance?

If no then how does compiler understand these statements?

D * d1 = new D;
d1->f0();    // statement 1

How does compiler interpret that f0() is function of B1 and since D has publicly inherited D it can access f0(). According to the article the compiler changes statement 1 to

(*B1::f0)(d)
+1  A: 

Aside from this, I can only say that a normal member function is just a memory address within a class (I even believe every object of that class use the same "function pointer" in memory, but with their own variables). A v-table is a form of runtime redirection, as the compiler can't know what object exactly it is dealing with (obviously due to polymorphism).

rubenvb
@rubenvb: Is there a separate table like vtable for all non-virtual functions, the pointer to which is stored in all class objects and which gets inherited by derived classes?
Bruce
@Bruce: see Amnon's answer for clarity, and adf88's answer for technicality.
rubenvb
+7  A: 

Non-virtual member functions are implemented like global functions that accept a hidden this parameter. The compiler knows at compile time which method to call based on the inheritance tree, so there's no need for a runtime table.

Amnon
+1  A: 

Is there a separate table like the v-table in which all the function addresses are stored?

They are stored in the place where they are called.

Taking your example: As long as the f0 method is non-virtual, the compiler knows what's the address of it because there is only one possibility. Let the address be 0xABCD. Then the code

d1->f0();    // statement 1

is compiled to instructions:

// push onto the stack 'this' pointer, as you pointed out the address must
// be earlier translated from D class to B1 which is not presented here
push d1

call 0xABCD // call method at known address (jump to this address)
adf88