In the last post we learnt about the event loop and how and why you should avoid blocking it. Another concept that you might have already stumbled upon is the meta-object system. If you have gone through the compile output of a Qt project you should have seen some traces of it; the output looks a bit different compared to compiling standard C++ code. If you haven't done it already, try to compile one of the Qt examples. See if you can spot something unusual about the output. This is the second post in the series "Crash course in Qt for C++ developers" covering the Meta-object system (including QObject and MOC). The other topics are listed below. Let's go back to the Qt example. Did you really compile it? Did you see something like...? Automatic MOC for target... Qt includes some C++ extension compilers which automatically generate extra code and files before compilation and linking. The Meta-Object Compiler, or MOC for short, is a tool that parses all header files in the project. Depending on what's defined in them, the tool might (see Qt has been criticised by some developers for this extra compilation step. However, it's done for good reasons. If you're interested in why such a decision was made, Qt has composed an interesting article which has got you covered. The generated moc_-files implement functions which are used for several different features. The perhaps most important ones are the signals and slots mechanism, the run-time type information (RTTI), and the dynamic property system. The first feature, signals and slots, is the main reason for introducing the MOC system and is also a big subject on its own. Therefore, a whole post will be dedicated to it; look for the next post in the series. This post will cover the last two: run-time type information and the dynamic property system as well as a very special object called the You might wonder what's so special about the Although the Actually, this is probably what most of your Qt classes will look like. By subclassing MyClass You might now think "This is nothing new! It is already supported in C++ using Yes, true! However, the Qt system doesn't require native RTTI compiler support. In addition, without a RTTI supported compiler, it's still possible to perform dynamic casts on Did you see the macro In addition to RTTI, the class can now be extend with properties. Qt's property system is extremely flexible and works cross-platform without relying on any non-standard compiler features. In fact Qt's property system is so powerful that you can dynamically create properties during run-time, such as: which will, as expected, output: Hello world There are several reasons why you'd want to extend your class with properties instead of using the standard member variables. I believe the main usage is to export them to the QML engine, which will be covered in a future post. To add properties to the class, the macro where the first argument is the type followed by the name of the property. The READ and WRITE accessors corresponds to getters and setters, whereas NOTIFY is optional and used to specify a signal (more on this in the next post). These are only some of the basic functionality that the property system provides, however it can be extended with many more features which you can read more about here. Let's extend our class with a couple of properties: We've only added two getters and setters; each getter and setter pair for each property. It's now possible to, for example, loop through the properties by using the which outputs: name: "DeLorean" values are stored as QVariants. A If you'd like to explore the full example code, feel free to fork the following GitHub project: and browse to In this post we've covered MOC, Qt's RTTI, qobject_cast and the property system. These features are very impressive alone, however by using the As a final point, I would like to mention that, although the See you next time!
Q_OBJECT
below) generate a companion file for a class named moc_class-name.cpp. To enable the MOC step, have a look at the Qt documentation or if you're familiar with CMake: just add AUTOMOC ON
as a property to the target. QObject
. The man, the myth, the QObject
QObject
. In order to do any of the aforementioned concepts in Qt you must subclass a QObject
and for signals and slots you'll also have to define the macro Q_OBJECT
in the class. Actually, just to get a sense of how important the object is, all Qt identity objects inherit from the QObject
. And there are many of them in the framework. Q_OBJECT
is optional when subclassing a QObject
, the official documentation recommends to always do it: without it, some functions may result in unexpected behaviour. The macro Q_OBJECT
is what the MOC is looking for in order to generate the moc_-file. A typical example of a Qt class will look like this:#include <QObject>
class MyClass : public QObject {
Q_OBJECT
Q_DISABLE_COPY(MyClass)
// ... properties ...
public:
MyClass();
// ... functions and member variables ...
};
QObject
we have now enabled the meta-object system and can now retrieve some runtime information about the class, such as the name of it:MyClass myclass;
qDebug() << myclass.metaObject()->className();
qDebug()
provides an output stream which can be used for debugging information, i.e. the code above will output:
typeid(myclass).name()
". QObjects
using qobject_cast() instead of the traditional C++ dynamic_cast()
. qobject_cast
even works across dynamic library boundaries.Q_DISABLE_COPY(MyClass)
defined in the class? It is, not surprisingly, used to prevent users from copying or moving the object. This is by design and I've written another blog post which is covering the reasons behind this: why qobject subclasses are not copyable.Qt's sophisticated property system
MyClass myclass;
myclass.setProperty("text","Hello world");
qDebug() << myclass.property("text").toString();
Q_PROPERTY
is used, for example:Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
class MyClass : public QObject {
...
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QString creator READ creator WRITE setCreator)
...
public:
...
const QString& name() const;
void setName(QString name);
const QString& creator() const;
void setCreator(QString creator);
private:
QString m_name{"DeLorean"};
QString m_creator{"Dr. Emmett Brown"};
};
QMetaObject
and print them: MyClass myclass;
const QMetaObject* metaobject = myclass.metaObject();
int count = metaobject->propertyCount();
for (int i{0}; i < count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const char* name = metaproperty.name();
QVariant value = myclass.property(name);
qDebug() << name << ": " << value.toString();
}
creator: "Dr. Emmett Brown"QVariant
is used as union for most Qt data types.
/04-sep-2018/example
.QObject enables even more features
meta-object system
you'll gain many more. Here are some of them:
QObjects
enable translations of strings for internationalisation using tr().QObjects
can receive and filter QEvents
. QObjects
can be used with guarded pointers which are automatically set to 0 after deletion.QObjects
, Q_OBJECT
and the MOC enable the perhaps most powerful feature of them all: the seamless inter-object communication signals and slots
, which will be covered in the next post.QObject
is extremely useful, the overhead of subclassing a QObject
is rather significant. It should probably be avoided if you're not going to use any of its features. Plain data structures shouldn't also inherit from QObjects
since they then won't be copyable or movable.