Click here to Skip to main content
15,885,309 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello everyone,

The project I'm currently working on uses Qt and OpenGL. Not that it matters for the question, really.

On my QMainWindow I want a pointer to a "Widget" that I'll use to implement all common functionalities in the widgets I write from now on. On the other hand, I'll also need to inherit from QGLWidget. So this is what I wrote:

C#
QWidget
Widget : public QWidget
QGLWidget : public QWidget (looked it up)
GLWidget : public QGLWidget, public Widget


This is an instant diamond problem. So I looked up for solutions and found out about "virtual inheritance". If I got this right, using virtual inheritance I get only one instance of the common base class, even though the vtable gets bigger. So I wrote this:

C#
QWidget
Widget : public virtual QWidget
QGLWidget : public QWidget
GLWidget : public virtual QGLWidget


To questions, then:

1) Does this do what I think it does? I mean, do I get only one instance of each class if I inherit (yet again) from either Widget or GLWidget (they are supposed to be used as base classes).

2) What about constructor propagation? Say I'm implementing QGLWidget. Where do I propagate the constructor call? Widget? QGLWidget? Or both?

Thank you all in advance =)
Kind regards
Posted
Updated 3-Feb-12 5:38am
v2
Comments
Sergey Alexandrovich Kryukov 3-Feb-12 6:33am    
Short answer: no, this is not correct. The effect of virtual base is different.
Can't you see that the instance of base class always comes in one instance, no matter what?

I have no time right now, will try to come back later.
What if you simply read about the subject?
--SA
AndreFratelli 3-Feb-12 7:42am    
I did read about it. That's how I got this questions in the first place =)

What do you mean no matter what? Isn't that what virtual inheritance is supposed to do? =\

Thanks!
Sergey Alexandrovich Kryukov 3-Feb-12 13:47pm    
I'm not sure, maybe you understand things correctly and only your wording was inaccurate, so I did not understand, but...

I mean this: "I mean, do I get only one instance of each class if I inherit".
First, you don't have instance if each class, you have just one instance, only of the class you inherit. This instance carries members of all classes you inherit. No matter what. But not instance of those classes. No matter if you have a virtual or non-virtual base classes. The instance of the class only "feels" the difference between virtual and non-virtual on another level of inheritance (that is when you have minimum 3 levels in hierarchy, and at least one diamond present). In most derived class, some inherited members are merged together and act like only one member in case of virtual base (very top of the diamond) and like different members in case of non-virtual base. This is what happen in reality. You should admit that this is very different from your description.
--SA
Sergey Alexandrovich Kryukov 3-Feb-12 15:44pm    
Please see my comments to the answer by Stephan_Lang and use the first of his links (first one).

Actually, create exactly 6 classes:
DiamondBase with public member "data",
DiamondA, DiamondB derived from virtual DiamondBase
DiamondC, DiamondC derived from DiamondBase (non-virtual)
DiamondTop derived from ...A, B, C, D

Create an instance of DiamondTop. You will have 3 (not 4) instances of "data". Manipulate all of them. You will see how they work.

Write a constructor for all 6 types and write some message to a console in each -- you will how constructor calls a chained. (I don't know what do you mean by "propagation", can only guess).

Based on this understanding, analyze more complex cases. That's it.
If you still can sort it out, ask me to make a detailed post for you. Ask what is not clear.

Good luck,
--SA

Check out http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9[^] or http://www.cprogramming.com/tutorial/virtual_inheritance.html[^]

Note that to solve your problem, both intermediate derived classes must inherit virtually, not just one of them.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 3-Feb-12 15:37pm    
My 5 -- first of the references is already good to understand things. OP should infer all consequences of this speculating from the basic definitions. OP might need tons of clarifications though, I'm not sure.

Different types of inheritance can be combined on every level and every member of inheritance list, making the picture more complex; and it can be easily analyzed on a case-to-case basis, but it's not easy to make a really good code design using those principles.

--SA
Stefan_Lang 6-Feb-12 5:34am    
Thank you SA.

I can only agree to your words of warning. Inheritance, and especially multiple inheritance, can easily obscure the true complexity of a system to the point where it appears to be taking on a life of its own.

Sometimes, less is more...
If you change
C++
class GLWidget : public QGLWidget, public Widget { }

to
C++
class GLWidget : public virtual  QGLWidget { }

you won't achieve the same as in the first example, because any methods exposed by Widget will not be available on an instance of GLWidget (as they would be in the first example), since you've completely removed Widget from the inheritance tree.

To get the initial inheritance tree, but with only one instance of each parent (virtual inheritance) you could go for something like this;

C++
#include<iostream>

using namespace std;

class QWidget
{
public:
	int value;

	QWidget(int param)
	{
		value = param;
	}

	virtual ~QWidget()	{ }
};

class Widget : public virtual QWidget
{
public:
	Widget(int paramA, int paramB)
		: QWidget(paramA * 10)
	{
	}

	virtual ~Widget()	{ }
	virtual void Foo()	{ }
};

class QGLWidget : public virtual QWidget
{
public:
	QGLWidget(int paramA, int paramB, int paramC)
		: QWidget(paramA)
	{
	}

	virtual ~QGLWidget() { }
};

class GLWidget : public virtual QGLWidget, public virtual Widget 
{
public:
	GLWidget(int paramA, int paramB, int paramC, int paramD)
		:  QGLWidget(paramA, paramB, paramC), Widget(paramA, paramB), QWidget(45)
	{
	}

	virtual ~GLWidget()	{ }
};

int main(int argc, char* argv[])
{
	GLWidget w(1, 2, 3, 4);
	cout << w.value << endl;
	w.Foo();
	return 0;
}


Notice that you will have to specify constructor arguments all the way down though, this example prints 45 for example (as the constructor of not only QGLWidget and Widget are called from the GLWidget constructor but also that of QWidget).

Hope this helps,
Fredrik
 
Share this answer
 
Comments
Stefan_Lang 3-Feb-12 9:52am    
You don't need virtual inheritance for GLWidget. I think it doesn't change anything, but in any case it's not needed. Only the intermediary derived classes must inherit virtually.
AndreFratelli 3-Feb-12 11:24am    
QWidget and QGLWidget are Qt classes, so I really can't do anything.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900