Access parent from child class
-
Hi, I have a Child class like this
MyChild::MyChild(QObject *parent) : QObject{parent} {
I want to call some parent's function from this Child class, I found calling from Child's constructor and Child's member funcion is different.
1. Calling from Child's constructor:
MyChild::MyChild(QObject *parent) : QObject{parent} { qobject_cast<MyParent *>(parent()); // ERROR: called object type 'QWidget *' is not a function or function pointer
Fix:
qobject_cast<MyParent *>(parent); // without (), I guess this is calling the passed param QObject *parent
or:
qobject_cast<MyParent *>(this->parent()); // using this->
2. Calling from Child's member function:
qobject_cast<MainVisualizer *>(parent()); // is OK
My question is why I cannot directly call parent() in constructor?
-
Hi, I have a Child class like this
MyChild::MyChild(QObject *parent) : QObject{parent} {
I want to call some parent's function from this Child class, I found calling from Child's constructor and Child's member funcion is different.
1. Calling from Child's constructor:
MyChild::MyChild(QObject *parent) : QObject{parent} { qobject_cast<MyParent *>(parent()); // ERROR: called object type 'QWidget *' is not a function or function pointer
Fix:
qobject_cast<MyParent *>(parent); // without (), I guess this is calling the passed param QObject *parent
or:
qobject_cast<MyParent *>(this->parent()); // using this->
2. Calling from Child's member function:
qobject_cast<MainVisualizer *>(parent()); // is OK
My question is why I cannot directly call parent() in constructor?
@dalishi said in Access parent from child class:
I want to call some parent's function from this Child class
As a starting point, this is (usually at minimum) a really bad idea/architectural design. It tends towards breaking half the point of OOP. Why would you want to do this?
I found calling from Child's constructor and Child's member funcion is different.
I don't think so.
qobject_cast<MyParent *>(parent()); // ERROR: called object type 'QWidget *' is not a function or function pointer
The error is correct. What do you think
parent()
(same for anyQObject *
, or indeed any non-function-pointer) should do?qobject_cast<MyParent *>(parent); // without (), I guess this is calling the passed param QObject *parent
This at least is "correct", but pointless as it stands. It does not call anything, that is important to understand. It (tries to) cast
parent
to aMyParent *
, and then throws away the result, which is essentially a no-operation.qobject_cast<MainVisualizer *>(parent()); // is OK
Because elsewhere than the constructor
parent
is a different thing.Let's go back. Your constructor is declared as
MyChild::MyChild(QObject *parent)
That makes
parent
a variable here, passed as a parameter. You cannot callparent()
on that, it doesn't make sense.Quite separately, anything derived from
QObject
has a QObject *QObject::parent() const member method --- which actually returns theparent
parameter originally passed to the constructor.this->parent()
will call that.parent()
on its own will call that within the class, unless there is variable namedparent
in scope, as in the constructor. So that's the answer for your confusion.Back to your original architecture: why are you wanting to cast the parent of your
MyChild
widget to see if it is aMainVisualizer
? You really should not need to be doing this, there is likely to be a much better way of arranging things. -
@dalishi said in Access parent from child class:
I want to call some parent's function from this Child class
As a starting point, this is (usually at minimum) a really bad idea/architectural design. It tends towards breaking half the point of OOP. Why would you want to do this?
I found calling from Child's constructor and Child's member funcion is different.
I don't think so.
qobject_cast<MyParent *>(parent()); // ERROR: called object type 'QWidget *' is not a function or function pointer
The error is correct. What do you think
parent()
(same for anyQObject *
, or indeed any non-function-pointer) should do?qobject_cast<MyParent *>(parent); // without (), I guess this is calling the passed param QObject *parent
This at least is "correct", but pointless as it stands. It does not call anything, that is important to understand. It (tries to) cast
parent
to aMyParent *
, and then throws away the result, which is essentially a no-operation.qobject_cast<MainVisualizer *>(parent()); // is OK
Because elsewhere than the constructor
parent
is a different thing.Let's go back. Your constructor is declared as
MyChild::MyChild(QObject *parent)
That makes
parent
a variable here, passed as a parameter. You cannot callparent()
on that, it doesn't make sense.Quite separately, anything derived from
QObject
has a QObject *QObject::parent() const member method --- which actually returns theparent
parameter originally passed to the constructor.this->parent()
will call that.parent()
on its own will call that within the class, unless there is variable namedparent
in scope, as in the constructor. So that's the answer for your confusion.Back to your original architecture: why are you wanting to cast the parent of your
MyChild
widget to see if it is aMainVisualizer
? You really should not need to be doing this, there is likely to be a much better way of arranging things.@JonB Hi thanks for your detailed reply. I'm sorry this is a typo, actually the "parent" here in my project is called MainVisualizer, an OpenGL widget as the main widget for the window. I just changed MainVisualizer to MyParent for simple description of the question here. So it should be
qobject_cast<MyParent *>(parent()); // is OK
But anyway, according to your point, calling parent's methods from child is a bad idea in OOP? Can you help elaborate more on this? I would desperately like to improve my architectural design. Thanks.
-
@JonB Hi thanks for your detailed reply. I'm sorry this is a typo, actually the "parent" here in my project is called MainVisualizer, an OpenGL widget as the main widget for the window. I just changed MainVisualizer to MyParent for simple description of the question here. So it should be
qobject_cast<MyParent *>(parent()); // is OK
But anyway, according to your point, calling parent's methods from child is a bad idea in OOP? Can you help elaborate more on this? I would desperately like to improve my architectural design. Thanks.
@dalishi said in Access parent from child class:
qobject_cast<MyParent *>(parent()); // is OK
It's "OK", but unless you go
MyParent *something = qobject_cast<MyParent *>(parent());
, and then usesomething
it is a pointless statement as you wrote it.calling parent's methods from child is a bad idea in OOP?
Indeed. Within reason, a child should not need/want to call methods of its parent, and ought to be independent of it. You are doing two "questionable" things here:
- First, why do you want to access anything about the parent in the child?
- Second, further you (attempt to) cast the parent to a
MainVisualizer *
. Why do you do that? Can yourMyChild
be called with anything other than aMainVisualizer *
as its parent anyway? If the answer is it cannot/must not, define yourMyChild
constructor asMyChild::MyChild(MainVisualizer *parent)
anyway. But this still does not answer why you want to call/access stuff from the parent/MainVisualizer
at all? There may be a good case, but without knowing what you are trying to achieve it's hard to say.
-
@JonB Hi thanks for your detailed reply. I'm sorry this is a typo, actually the "parent" here in my project is called MainVisualizer, an OpenGL widget as the main widget for the window. I just changed MainVisualizer to MyParent for simple description of the question here. So it should be
qobject_cast<MyParent *>(parent()); // is OK
But anyway, according to your point, calling parent's methods from child is a bad idea in OOP? Can you help elaborate more on this? I would desperately like to improve my architectural design. Thanks.
@dalishi said in Access parent from child class:
calling parent's methods from child is a bad idea in OOP?
Doing so means that your child knows details about its parent. If you later use your child class with another parent (different class) then your code will not work anymore because child makes assumptions about its parent. You're basically introducing tightly coupled code. So, child should not know anything about its parent. If child needs to communicate with parent signals/slots should be used in Qt.
-
@dalishi said in Access parent from child class:
qobject_cast<MyParent *>(parent()); // is OK
It's "OK", but unless you go
MyParent *something = qobject_cast<MyParent *>(parent());
, and then usesomething
it is a pointless statement as you wrote it.calling parent's methods from child is a bad idea in OOP?
Indeed. Within reason, a child should not need/want to call methods of its parent, and ought to be independent of it. You are doing two "questionable" things here:
- First, why do you want to access anything about the parent in the child?
- Second, further you (attempt to) cast the parent to a
MainVisualizer *
. Why do you do that? Can yourMyChild
be called with anything other than aMainVisualizer *
as its parent anyway? If the answer is it cannot/must not, define yourMyChild
constructor asMyChild::MyChild(MainVisualizer *parent)
anyway. But this still does not answer why you want to call/access stuff from the parent/MainVisualizer
at all? There may be a good case, but without knowing what you are trying to achieve it's hard to say.
@JonB Hi, the case where I want to access the parent is like this: Suppose I have a main widget (MainVisualizer OpenGLWidget), and I have a QDialog (e.g. ConfigDialog) to set some values and the corresponding drawing in the MainVisualizer will change accordingly.
Previously I would make the ConfigDialog instance the child of the main widget, and in the ConfigDialog once I need to update the drawing, I directly call its parent i.e. the MainVisualizer's method.
Now according to your comment, I guess I could use signal and slot instead. When the configdialog sends a signal, the mainvisualizer will have a slot to deal with the update drawing. In such way the ConfigDialog (Child) and MainVisualizer (Parent) are independent of each other.
-
@dalishi said in Access parent from child class:
calling parent's methods from child is a bad idea in OOP?
Doing so means that your child knows details about its parent. If you later use your child class with another parent (different class) then your code will not work anymore because child makes assumptions about its parent. You're basically introducing tightly coupled code. So, child should not know anything about its parent. If child needs to communicate with parent signals/slots should be used in Qt.
@jsulm Hi thanks for the reply. Yes! I assume the child knows who is its parent and that's why I use object_cast to cast the Widget* to MyParent*. It is indeed tightly coupled. I realize this is not the "correct" way to implement with QT. Signal-Slot is the way to go. Thanks.
-
@JonB Hi, the case where I want to access the parent is like this: Suppose I have a main widget (MainVisualizer OpenGLWidget), and I have a QDialog (e.g. ConfigDialog) to set some values and the corresponding drawing in the MainVisualizer will change accordingly.
Previously I would make the ConfigDialog instance the child of the main widget, and in the ConfigDialog once I need to update the drawing, I directly call its parent i.e. the MainVisualizer's method.
Now according to your comment, I guess I could use signal and slot instead. When the configdialog sends a signal, the mainvisualizer will have a slot to deal with the update drawing. In such way the ConfigDialog (Child) and MainVisualizer (Parent) are independent of each other.
@dalishi said in Access parent from child class:
and in the ConfigDialog once I need to update the drawing, I directly call its parent i.e. the MainVisualizer's method.
Yes, that's the bit we don't like, if we are making an OOP effort.
Now according to your comment, I guess I could use signal and slot instead. When the configdialog sends a signal, the mainvisualizer will have a slot to deal with the update drawing. In such way the ConfigDialog (Child) and MainVisualizer (Parent) are independent of each other.
Exactly that! Or, if you only need to act on the selections in the configuration dialog once the user has made them (possibly several different ones) and pressed some OK button, you could either have the dialog pass back some
struct
with the various options filled in or you could keep the dialog instance alive for a second (though not shown) and have it provide getter methods which return the values separately for the main window to call. Either way, or with signals & slots, it is the main window which picks up the results and acts on them, not the child which "pokes" them into the parent.If your configuration dialog is modal I think it "more usual" that all changes are gathered together and acted on at the end than changes are made immediately to reflect in the main window (as would be the case with either calling parent methods or acting on signals). I'm not sure I can think of modal dialogs where changes are reflected in the caller at the instant they are made. If it were a modeless dialog/window that might be different.