Reputation: 1525
In C++ Qt there is a class QWidget
A
inherits QWidget
and adds some featuresB
inherits A
and adds some featuresC
inherits B
and adds some features, C
must be of type QWidget
and should do all things done by B
For some reason C
is not behaving as expected, I have to rewrite class C
. I can not modify code up to class B
creation.
How can I solve this problem? Any design pattern, or anything else?
If I try to inherit QWidget
and B
, a multiple inheritance, there will be two QWidget
which leads to problem (QObject - moc does not allow it).
If I inherit from QWidget
and pass object of B
to C
's constructor, whatever operation B
performs applies to another QWidget
coming through B
, which is not desired, all features provided by B
should apply to my C
's QWidget
.
Upvotes: 0
Views: 140
Reputation: 98435
Suppose there is a temperature sensor, when that gets disconnected from machine, class
B
draws a content blocker image on the whole area ofQWidget
that it owns, I can monitor sensor connect /disconnect and supposeC
's fun.OnDisconnect()
gets called, I will callB::OnDisconnect()
,B
will draw blocker image on its ownQWidget
, not on the one which is owned byC
.
This has everything to do with C++'s rather inflexible method implementation inheritance when compared e.g. to the Common LISP Object System.
Since B
's obscuration is always meant to be on top of B
's contents, what you effectively need is for B
to provide an overlay that draws on top of its contents, even if paintEvent
is overriden in derived classes.
See this answer for a simple example, or another answer for an overlay with blur graphical effect.
This is fairly easy to accomplish by having B
add an optional overlay widget to itself.
Example:
class OverlayWidget; // from https://stackoverflow.com/a/19367454/1329652
class ObscureOverlay : public OverlayWidget
{
public:
ObscureOverlay(QWidget * parent = {}) : OverlayWidget{parent} {}
protected:
void paintEvent(QPaintEvent *) override {
QPainter p{this};
p.fillRect(rect(), {Qt::black});
}
};
class A : public QWidget {
...
protected:
void paintEvent(QPaintEvent *) override { ... }
};
class B : public A {
...
ObscureOverlay m_obscure{this};
public:
B() {
m_obscure.hide();
}
Q_SLOT void OnDisconnect() {
m_obscure.show();
...
}
};
class C : public B {
...
protected:
void paintEvent(QPaintEvent * event) override {
B::paintEvent(event);
...
}
};
If you don't have the source code to B
, you can add the overlay to C
, replicating original B
's functionality when obscured. All of Qt's slots are effectively virtual, so if you pass a C
to someone expecting B
and connecting to its OnDisconnect
slot, it will be C
's slot that will get invoked.
class C : public B {
Q_OBJECT
...
ObscureOverlay m_obscure{this};
public:
explicit C(QWidget * parent = {}) : B{parent} {
m_obscure.hide();
}
Q_SLOT void OnDisconnect() { // slots are effectively virtual
m_obscure.show();
B::OnDisconnect();
}
protected:
void paintEvent(QPaintEvent * event) override {
B::paintEvent(event);
QPainter p{this};
...
}
};
Upvotes: 1