Question about virtual inheritance

Jun 22, 2012 at 9:46pm
Hello,

I have a few questions about virtual inheritance. When inheriting from a base class virtually, only one base class will be created to be shared with all the base class's direct-children classes.

First off, I am working with this code (using a pastebin site for neatness):

http://ideone.com/j7ncq

In this code, I follow the "diamond" problem format, and use virtual inheritance to create only Animal only once. The output appeared as expected:


Creating Animal
Creating FourLegs
Creating Mammal
Creating Fox


Now, I was curious about what would happen if only one child class inherited virtually, while the other inherited normally.

This time, I inherited FourLegs virtually and Mammal regularly.

http://ideone.com/xyEMG

The result was the same as if their was no virtual inheritance in the first place:


Creating Animal
Creating FourLegs
Creating Animal
Creating Mammal
Creating Fox


Now, I tried it the other way around. I inherited FourLegs normally and Mammal virtually.

http://ideone.com/WBFdF

This was the result that surprised me most and have no idea on how it came to be.


Creating Animal
Creating Animal
Creating FourLegs
Creating Mammal
Creating Fox


Could somebody mind explaining to me how these results came to be?
Last edited on Jun 23, 2012 at 12:20am
Jun 22, 2012 at 10:02pm
closed account (zb0S216C)
Without virtual inheritance, Mammal will inherit from Animal, and FourLegs will also inherit from Animal; each will have their own copy of Animal's data members and member functions.

When Fox inherits from Mammal and FourLegs, Fox will have two copies of Animal. As a result, when a Fox is constructed, two Animals, 1 Mammal, 1 FourLegs, and 1 Fox are constructed; thus, multiple Animal construction.

So how do you distinguish between the two inherited Animal classes? Simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Animal
{
public:
    Animal() : a(0)
    {
        std::cout << "Creating Animal\n";
    }
    int a; // New data member for this example.
};

///////////////////////////

class FourLegs : public Animal
{
public:
    FourLegs()
    {
        std::cout << "Creating FourLegs\n";
    }
};

///////////////////////////

class Mammal : public Animal
{
public:
    Mammal()
    {
        std::cout << "Creating Mammal\n";
    }
};

///////////////////////////

class Fox : public FourLegs, public Mammal
{
public:
    Fox()
    {
        std::cout << "Creating Fox\n";
    }
};

int main()
{
    Fox fox_;

    // Get "a" from Mammal's Animal:
    fox_.Mammal::a;

    // Get "a" from FourLegs' Animal:
    fox_.FourLegs::a;
}

With virtual inheritance, the compiler will only construct 1 Animal object for both Mammal and FourLegs. However, this will only take place if Mammal and FourLegs are inherited into a common class, just like Fox.

Wazzak
Last edited on Jun 22, 2012 at 10:05pm
Jun 22, 2012 at 10:53pm
Yeah, I understand that you can specify what you want to access using the :: operator, but virtual inheritance can be helpful if you do not want to create that extra Animal.
Jun 23, 2012 at 5:17pm
Any ideas on how virtual inheritance works?
Jun 23, 2012 at 5:52pm
The diamond format is called the Deadly diamond, because you are inheriting the same base class twice. Do a search for "mix-in classes" on google or wikipedia. The way your classes are set up you inherit a base class multiple times (as in your code) you get a major concern. lets say you have class who has 'X' method(s)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream.h>
using std::cout;
using std::end;

class A{
public:
 virtual void doSomething()=0;
};

class B : public A //implements doSomething
{
public:
   void doSomething(){
    cout<< "I do something" << endl;
}
};

class C: public A
{
public:
void doSomething(){
  cout<<"I do something else" << endl;
}
};

class D: public B, public C //oops multiple inheritance which do something does the          //compiler call?
{
  //oops houston we have a problem
};

int main()
{
   A* a = new D();

if( a == 0 ) return -1;

 a->doSomething();//oh no

delete a;

a = 0;

return 0;
}
Last edited on Jun 23, 2012 at 5:52pm
Jun 23, 2012 at 6:17pm
so, do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;

class A{
public:
 virtual void doSomething()=0;
};

class B : virtual public A //implements doSomething it needs to be virtual until the root
{
public:
   void doSomething(){
    cout<< "I do something" << endl;
}
};

class C: virtual public A //it needs to be virtual until the root
{
public:
void doSomething(){
  cout<<"I do something else" << endl;
}
};

class D: virtual public B, virtual public C //OK, virtual inheritance, so only 1 A;
{
  //houston we don't have a problem
};

int main()
{
   A* a = new D();

if( a == 0 ) return -1;

 a->doSomething();//oh no!
//rather a->B::doSomething() or a->C::doSomething();

delete a;

a = 0;

return 0;
}
Jun 23, 2012 at 6:29pm
@viliml I understand that if I were to do it the way in your example (with virtual methods until the root i would have no problem) however I used that example to clarify multiple inheritance gone wrong. The virtual identifier you used before public for each abstract class would be unnecessary if the derived classes did not implement the base class but rather inherited the function ptr. I like the way that you declared, for example:

 
class C: virtual public A{};//i did not know that you could explicitly declare the virtual, interesting. 
Last edited on Jun 23, 2012 at 6:29pm
Jun 23, 2012 at 6:34pm
@DeXipher just google "virtual base classes", and you'll find everything you need.
Jun 23, 2012 at 6:53pm
@DeXecipher

I am having trouble understanding parts of your code. Well first off, I haven't learned about virtual functions yet (I will soon).

However, I still have a question with one part of your code.

 
A* a = new D();


Is this possible with inheritance? You are allowed to have a parent class point equal to a child class? How would this work if they have different members?

But I do not want to derail from my first question. What happens if you have four classes that are like the "diamond problem". If I do not want two tier-3 classes to be created, the two tier-2 classes must be inherited virtually, as shown in my first link in the original post. I was just curious about what would happen if only one of the tier-2 classes was inherited virtually.
Last edited on Jun 23, 2012 at 6:54pm
Jun 23, 2012 at 7:09pm
@Flurite

Its not that the child class is "equal to the parent" but its more like the child class can be casted A* a = (A*)new D(); if D is a case of A.

This means that D inherits A. An Animal is not a Dog (An animal is any and all definitions fo animal), but a Dog is an Animal. A Square is a form of rectangle but a rectangle is not a form of square. Its an is a relationship between the Base class, A, and the child class D;

Thats one of the many uses of inheritance, it abstracts everything. Lets say you have many versions (implementations) of Animal but you only want one. Well you can cast any one of those implementations of Animal to the animal Interface and it will call the implementation of the animal implementation, ("Mammal") for instance, that you made.

Reedited:
as to your questions about the result, in your earlier post is because you use multiple inheritance. Its not just one animal constructor you are calling it is two. First the compiler calls the animal constructor in Fourlegs():Animal(), then Mammal():Animal(), then if calls Fourlegs(), then finally it will call the constructor Mammal();

This is why you get the statement: "Creating Animal" twice.


Last edited on Jun 23, 2012 at 7:17pm
Jun 23, 2012 at 7:44pm
@DeXecipher,

So if I cast a child class to a parent class pointer, are the unique properties of the child class (not in parent class) accessible from the pointer?

------

Which piece of code are you referring to? First? Second? Third?
Jun 23, 2012 at 8:49pm
The unique attributes of the child class are only visible if the parent class defines them in a manner that coincide with the child class. If this is what you mean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using std::cout;
using std::endl;

class A:{

private:

int i1;
public:

A(int i):i1(i){}

virtual int getInt(){return i1;}//this version returns i1;

};//abstract
class B: public A
{
private:
int i2;
public:
B(int i):i2(i){}
virtual int getInt(){return i2;}//this version returns i2;
};

int main()
{
A* foo = (A*)new B(10);//calling B's constructor
foo->getInt();

cout << foo->getInt() << endl;//calls B's version of getInit
//thus it accesses i2 instead of i1.

delete((*B)foo);

return 0;
}


edit: I forgot my semicolons at then of the classes, it should compile now
Last edited on Jun 24, 2012 at 12:52am
Jun 24, 2012 at 12:24am
I haven't learned much about virtual functions yet, so I cannot really understand your example. Anyhow, lets say I have something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class X
{
public:
int variable1;
};

class Y : public X
{
int variable 2;
};


int main()
{
X* myPntr = new Y;
return 0;
}


From myPntr, could I do this?

cout << myPntr->variable1 << myPntr->variable2 << "\n";

If not, which would cause the error?
Jun 24, 2012 at 12:28am
Variable variable2 has private access control. So you may not write

cout << myPntr->variable2 << "\n";
Jun 24, 2012 at 12:28pm
Oops, variable2 was supposed to be public. So that pretty much means that X can see all public variables of the child class and it is considered part of the pointer's members?

Also, how are virtually inherited classes created? If only one of the tier-2 classes are inherited virtually in the diamond problem, how is the result different?
Jun 27, 2012 at 12:23am
X can only see anything that it would actually have access to itself. You will not have access to any variables or functions in the child functions, unless you use virtual functions (This is where they come in handy, and is called polymorphism).

For example, your Animal class has an eat function:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal
{
public:
virtual void Eat(); //Declare it virtual
};
class Dog: public Animal
{
public:
virtual void Eat(); //Here we "overwrite" the original Eat function
};
//Now if you do something like this:
Animal *a = new Dog;
a->Eat(); //Dog's eat function will be called. 

That's what virtual functions are used for.
Topic archived. No new replies allowed.