moatPylon
moatPylon

Reputation: 2191

Multiple inheritance of virtual classes

Suppose I have the following code:

class a {
public:
    virtual void do_a() = 0;
}

class b {
public:
    virtual void do_b() = 0;
}

class c: public a, public b {
public:
    virtual void do_a() {};
    virtual void do_b() {};
}

a *foo = new c();
b *bar = new c();

Will foo->do_a() and bar->do_b() work? What's the memory layout here?

Upvotes: 0

Views: 239

Answers (7)

Praetorian
Praetorian

Reputation: 109279

As others have mentioned the following will work without any problems

foo->do_a();
bar->do_b();

These, however, will not compile

bar->do_a();
foo->do_b();

Since bar is of type b* it has no knowledge of do_a. The same is true for foo and do_b. If you want to make those function calls you must downcast.

static_cast<c *>(foo)->do_b();
static_cast<c *>(bar)->do_a();

The other very important thing that is not shown in your example code is, when inheriting, and referring to the derived class through base class pointer, the base class MUST have a virtual destructor. If it doesn't then the following will produce undefined behavior.

a* foo = new c();
delete a;

The fix is simple

class a {
public:
    virtual void do_a() = 0;

    virtual ~a() {}
};

Of course, this change needs to be made to b as well.

Upvotes: 2

Chad
Chad

Reputation: 19052

foo->do_a();   // will work
bar->do_b();   // will work
bar->do_a();   // compile error (do_a() is not a member of B)
foo->do_b();   // compile error (do_b() is not a member of A)

// If you really know the types are correct:
C* c = static_cast<C*>(foo);

c->do_a();  // will work
c->do_b();  // will work

// If you don't know the types, you can try at runtime:
if(C* c = dynamic_cast<C*>(foo))
{
    c->do_a();  // will work
    c->do_b();  // will work
}

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308520

Yes, of course it will work. The mechanics are a bit tricky though. The object will have two vtables, one for the class a parent and one for the class b parent. The pointers will be adjusted so that they point to the subset of the object that corresponds to the pointer type, leading to this surprising result:

c * baz = new c;
a * foo = baz;
b * bar = baz;
assert((void *)foo == (void *)bar); // assertion fails!

The compiler knows the types at the time of the assignment, and knows exactly how to adjust the pointers.

This is of course completely compiler dependent; nothing in the C++ standard says it has to work this way. Only that it has to work.

Upvotes: 1

Dhruv Gairola
Dhruv Gairola

Reputation: 9182

They will work. In terms of memory, this is implementation dependent. You have created objects on the heap, and for most systems, it is worth noting that objects on the heap grow upwards (c.f. the stack grows downwards). So possibly, you will have:

Memory:

+foo+
-----
+bar+

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385395

Will a->do_a() and b->do_b() work?

No.

Will foo->do_a() and bar->do_b() work?

Yes. Your code is the canonical example of virtual function dispatch.

Why didn't you just try it?

What's the memory layout here?

Who cares?

(i.e. this is implementation-defined, and abstracted from you. You should not need to nor want to know.)

Upvotes: 0

James Kanze
James Kanze

Reputation: 154027

Why shouldn't they? The memory layout will typically be something like:

+----------+
|  A part  |
+----------+
|  B part  |
+----------+
|  C part  |
+----------+

If you convert your foo and bar to void* and display them, you'll get different addresses, but the compiler knows this, and will arrange for the this pointer to be correctly fixed up when calling the function.

Upvotes: 3

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361732

Will a->do_a() and b->do_b() work?

Assuming you meant foo->do_a() and bar->do_b(), as a and b are not object, they're type, yes. They will work. Did you try run that?

What's the memory layout here?

That is implementation-defined, mostly. Fortunately, you don't need to know about that unless you want to write non-portable code.

Upvotes: 4

Related Questions