Extending 3rd party APIs (Qt) -- diamond inheritance problems..

Hello. I'm writing a UI library which uses Qt as a base, and I want each of my widgets to derive from my own version of QWidget which adds some base functionality I want them all to have. But then I run into issues when I want to extend, say, QLineEdit.

I am using Qt but I think this applies to any situation where there's an external API being used. For anyone unfamiliar with Qt, QLineEdit is a "QLineEdit : public QWidget".

So I have something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ZWidget : public virtual QWidget
{
    Q_OBJECT
public:
    ZWidget( QWidget * parent = 0 ) : QWidget(parent) {}

    // new base functions go here, for example:
    void setName( QString const & name );
};

// This is where I get confused
class ZLineEdit : public QLineEdit, public ZWidget
{
    Q_OBJECT
public:
    // It should still be parentable to a standard QWidget
    // What's the proper thing to do here?
    ZLineEdit( QWidget * parent = 0 ) : QLineEdit(parent) {}
};


My understanding is normally you'd want to define QLineEdit as a virtual QWidget and take it from there, but I don't have that kind of control in this case. Is there perhaps a different approach I should be considering? My main reason for desiring this is so that I can treat all these widgets in an abstract way (as ZWidgets) in certain situations.

Thanks. :)
Last edited on
I should elaborate with some example usage code:

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
// An example new base function
void ZWidget::setName( QString const & name )
{
    setObjectName( name );
}

QWidget * main_widget = new QWidget();
QVBoxLayout * layout = new QVBoxLayout( main_widget );

ZWidget * zwidget = new ZWidget( main_widget );
zwidget->setName( "zwidget" );
QVBoxLayout * layout2 = new QVBoxLayout( zwidget );

ZLineEdit * zlineedit = new ZLineEdit( zwidget );
zlineedit->setName( "zlineedit" );

ZLineEdit * zline2 = new ZLineEdit( zwidget );
zline2->setName( "zline2" );

ZLineEdit * zline3 = new ZLineEdit( main_widget );
zline3->setName( "zline3" );

layout2->addWidget( zlineedit ); // C2594
layout2->addWidget( zline2 ); // C2594

layout->addWidget( zwidget );
layout->addWidget( zline3 ); // C2594 


This code generates "ambiguous conversion" errors on the marked lines, a function which expects a QWidget *.
Last edited on
I always thought both classes in the middle of the diamond had to virtually inherit the base class.
As you have have control over ZWidget you can do that - but you are stuck with QLineEdit because
that is part of QT and I'm sure it does not virtually inherit QWidget.
Yep, that's exactly the problem I'm trying to solve. :-/
Maybe this will help someone in the future. The solution in this case is to use Qt interfaces. I create an interface class called, say, ZObject, declared it as a Qt Interface and proceed as such:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ZObject
{
public:
  // interface functions
};

Q_DECLARE_INTERFACE( ZObject, "com.whatever.zobject/1.0" )

class ZWidget : public QWidget, public ZObject
{
    Q_OBJECT
    Q_INTERFACES( RTObject )
public:
    // and so on
};


It's not perfect, but it will suffice. :) I won't be able to replace QWidget with my own extended ZWidget in my widgets as I originally intended, but some important features will be available. For example:

1
2
3
4
5
6
7
QWidget * widget = new ZWidget( parent );
if( qobject_cast<ZObject *>(widget) )
    // test passes, ZWidget inherits ZObject

// get a list of all my widgets
// guaranteed to have my new functions
QWidgetList widgets = widget->findChildren<ZObject *>();
Topic archived. No new replies allowed.