[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

At first, see
 virtual inheritance in wikipedia to know about virtual inheritance.

There are lots of articles about this. So, I am adding 'Real' example tested on "MSVC2005 Express".
- Don't use 'debug watch' of VC. Sometimes it show wrong information!.
(Note: C++ standard doens't define anything about the way of implementing dynamic polymorphism. So, results are dependent on compiler.)

==================================
Non-Virtual Inheritance
class Animal
{
  virtual void Eat(){};
  int animal;
};

Animal
  +-----------------+
  |   __vfptr       |---> Animal::Eat()
  +-----------------+
  |   int animal    |
  +-----------------+

class Mammal : public Animal
{
  virtual void Run(){};
  int mammal
};

Mammal
  +-----------------+
  |   __vfptr       |---> Animal::Eat()
  +-----------------+     Mammal::Run()
  |   int animal    |
  +-----------------+
  |   int mammal    |
  +-----------------+

class Winged : public Animal
{
  virtual void Flap(){};
  int winged
};

Winged
  +-----------------+
  |   __vfptr       |---> Animal::Eat()
  +-----------------+     Winged::Flap()
  |   int animal    |
  +-----------------+
  |   int winged    |
  +-----------------+

class Bat : public Mammal, public Winged
{
  virtual void Hang(){};
};

Bat
  +-----------------+
  |   __vfptr       |---> Animal::Eat() (*1) [from Mammal]
  +-----------------+     Mammal::Run()
  |   int animal    |     Bat::Hang()
  +-----------------+
  |   int mammal    |
  +-----------------+
  |   __vfptr       |---> Animal::Eat() (*2) [from Winged]
  +-----------------+     Winged::Flap()
  |   int animal    |
  +-----------------+
  |   int winged    |
  +-----------------+

(Address of (*1) and (*2) is different.)

======================================
Virtual Inheritance

class Animal
{
public:
  Animal():animal(){}
  virtual void Eat(){};
  int animal;
};

Animal
  +-----------------+
  |   __vfptr       |---> Animal::Eat()
  +-----------------+
  |   int animal    |
  +-----------------+

class Mammal : public virtual Animal
{
public:
  Mammal():mammal(){}
  virtual void Run(){};
  int mammal;
};

Mammal
  +-----------------+
  |   __vfptr       |---> Mammal::Run()
  +-----------------+
  |   ???????????   |
  +-----------------+
  |   int mammal    |
  +-----------------+
  |    __vfptr      |---> Animal::Eat()
  +-----------------+
  |   int animal    |
  +-----------------+

class Winged : public virtual Animal
{
public:
  Winged():winged(){}
  virtual void Flap(){};
  int winged;
};

Winged
  +-----------------+
  |   __vfptr       |---> Winged::Flap()
  +-----------------+
  |   ???????????   |
  +-----------------+
  |   int winged    |
  +-----------------+
  |    __vfptr      |---> Animal::Eat()
  +-----------------+
  |   int animal    |
  +-----------------+

class Bat : public Mammal, public Winged
{
  virtual void Hang(){};
};

Bat
  +-----------------+
  |   __vfptr       |---> Mammal::Run()
  +-----------------+     Bat::Hang()
  |   ??????????    |
  +-----------------+
  |   int mammal    |
  +-----------------+
  |   __vfptr       |---> Winged::Flap()
  +-----------------+
  |   ??????????    |
  +-----------------+
  |   int winged    |
  +-----------------+
  |    __vfptr      |---> Animal::Eat()
  +-----------------+
  |   int animal    |
  +-----------------+
===============================

NOTE: I have no idea what "?????" means. I think this is only for internal use of VC.

Here is view of this.

"---." : reference member (p.xxx)
"--->" : pointer member (p->xxx)

Non-virtual inheritance
  bat
  |----. Mammal
  | |----. Animal
  | | |----. __vfptr ( --> 0x00415770) --- (*1)
  | | | |----> Animal::eat(void)
  | | | |----> Mammal::setHairColor(void)
  |
  |----. WingedAnimal
  | |----. Animal
  | | |----. __vfptr ( --> 0x00415760) --- (*2)
  | | | |----> Animal::eat(void)
  | | | |----> WingedAnimal::flap(void)

Virtual inheritance case
  bat
  |----. Mammal
  | |----. Animal
  | | |----. __vfptr ( --> 0x00415788) --- (*3)
  | | | |----> Animal::eat(void)
  | |----. __vfptr
  | | |----> Mammal::setHairColor(void)
  |
  |----. WingedAnimal
  | |----. Animal
  | | |----. __vfptr ( --> 0x00415788) --- (*4)
  | | | |----> Animal::eat(void)
  | |----. __vfptr
  | | |----> WingedAnimal::flap(void)

We should focus on that pointed address indicated at (*1) and (*2) is different, but the one at (*3) and (*4) is same - actually, it's not separated entity, it's same one. That is, there is one vftable for Animal class.

Now we can know the way of virtual inheritance.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

See following example codes.

class A
{
public:
    virtual int a(void) {return 1; }
    virtual int b(void) {return 11;}
    int         c(void) {return 21;}
};

class B
{
public:
    virtual int a(void) {return 2; }
    virtual int b(void) {return 12;}
    int         c(void) {return 22;}
};

class C : public A, public B
{
public:
    virtual int a(void) { return 3; }
};

void main(void)
{
    C c;
    A* pa = &c;
    B* pb = &c;
    printf("%d / %d / %d\n", pa->a(), pb->a(), c.a()); // OK ---(*1)
    printf("%d\n", c.b());  // Compile Error due to ambiguous access ---(*2)
    printf("%d\n", c.c());  // Compile Error due to ambiguous access ---(*3)
}

In case of (*2) and (*3), Compiler gives 'Error' due to ambiguity - A::b()/B::b(). It's clear.
But, there is no ambiguity in case (*1). Function 'a' is declared as 'virtual' in A and B. And 'a' also overridden in C. So, all three parameters of 'printf' means 'C::a()'.

+ Recent posts