Table of Contents
[ fromfile: qobject.xml id: qobject ]
Abstract
QObject is the base class for many of the important classes in the Qt library, such as QEvent, QApplication, QLayout, and QWidget. A QObject can have a parent and children, providing another implementation of the Composite pattern. It can use signals and slots, an implementation of the Observer pattern, to communicate with other QObjects. QObjects make it possible to do event-based programming, which employs QApplication and Qt's event loop.
We refer to any object of a class publicly derived from QObject as a QObject. Following is an abbreviated look at its definition.
class QObject { public: explicit QObject(QObject* parent=0); QObject * parent () const; QString objectName() const; void setParent ( QObject * parent ); const QObjectList & children () const; // ... more ... };
QObject does not have a public
copy
constructor or copy assignment operator.
Down toward the end of its class definition there is a macro (Q_DISABLE_COPY(QObject)) that explicitly makes sure
that no QObject can be copied.
QObject
s
are not meant to be copied.
In general, QObject
s
are intended to represent unique objects with identity; that is, they correspond to real-world things that have
some sort of persistent identity.
One immediate consequence of this no-copy policy is that a QObject can never be passed by value to any function. Copying a QObject's data members into another QObject is still possible, but the resulting two QObjects are considered distinct.
explicit Constructors |
|
---|---|
Single-argument constructors of QObject
(and derived classes) should be designated |
Each QObject can have (at most) one parent QObject, and an arbitrarily large
number of QObject children.
In other words, the type of each child must be QObject or must be
derived from QObject.
Each QObject stores pointers to its
children in a QObjectList
[61].
The list itself is created in a lazy-fashion to minimize the overhead for objects that have no children.
Because each child is a QObject and can have an arbitrarily
large collection of children, it is easy to see why copying QObject
s
is not permitted.
The notion of children can help to clarify the notion of identity and the no-copy policy for QObject
s.
If you represent individual humans as QObject
s,
the idea of a unique identity for each QObject is clear.
Also clear is the idea of children.
The rule that allows each QObject to have at most one parent can
be seen as a way to simplify the implementation of this class.
Finally, the no-copy policy stands out as a clear necessity.
Even if it were possible to "clone" a person (i.e., copy its data members to another QObject), the question of what to do
with the children of that person makes it clear that the clone would be a separate and distinct object with a
different identity.
Each QObject parent manages its children. This means that the QObject's children are destroyed during its destructor call.
The child list establishes a bidirectional association between QObjects:
Each parent object knows the address of each of its child objects.
Each child object knows the address of its parent object.
Setting the parent of a QObject implicitly adds its address to the child list of the parent; i.e.,
objA->setParent(objB);
adds the objA
pointer to the child list of objB
.
If you subsequently have
objA->setParent(objC);
then the objA
pointer is removed from the child list of objB
and added to the child list of objC
.
Such an action is called reparenting.
As you saw earlier, the widgets of a graphical user interface (GUI) are all derived from QWidget, which is derived from QObject. As with QObjects, we refer to any object of a class publicly derived from QWidget as a QWidget (or sometimes, simply, widget). In a GUI, the parent-child relationships are usually visible: Child widgets appear inside parent widgets. In Figure 8.1, the dialog widget has several children, including: A label widget, a line edit widget, and two pushbutton widgets. It also has a title bar widget, which may be a parent or sibling of the dialog. It is usually provided by the window manager, and contains several child widgets, including the button widgets that enable a user to minimize, maximize, or close the dialog.
The need for the child management requirement is also visible in Figure 8.1. When you close the dialog (e.g., by clicking on the small button in the upper-right corner), you want the entire dialog window to vanish from the screen (i.e., to be destroyed). You don't want pieces of it (e.g., the odd button or label widget) to linger on the screen, and you don't want to put the burden of all that cleanup on the programmer. That is why each QObject is responsible for destroying all its children when its destructor is called. This is a naturally recursive process. When a QObject is to be destroyed, it must first call the destructor for each of its children; each child object must then call the destructor for each of its children; and so forth.
Now consider some of the problems that would arise if it were possible to copy a QObject. For example, should the copy have the same parent as the original? Should the copy have (in some sense) the children of the original? A shallow copy of the child list would not work because then each of the children would have two parents. In that case, if the copy needs to be destroyed (e.g., if the copy was a value parameter in a function call), each child needs to be destroyed too (because the QObject must manage its children). Even with resource sharing methods, this approach would introduce some serious difficulties. A deep copy of the child list could be a costly operation if the number of children were large and the objects pointed to were large. Because each child could also have arbitrarily many children, this questionable approach would also generate serious difficulties.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |