Saturday, March 7, 2009

Qt : Meta Object System

Meta Object System

Qt's Meta Object System provides the signals and slots mechanism for inter-object communication, runtime type information, and the dynamic property system.

A meta object is an object that describes the structure of another object. It provides information about properties and methods of a QObject. The MetaObject pattern is sometimes known as the Reflection pattern.

The Meta Object System is based on three things:

    * the QObject class;
    * the Q_OBJECT macro inside the private section of the class declaration;
    * the Meta Object Compiler (moc).

The moc reads a C++ source file. If it finds one or more class declarations that contain the Q_OBJECT macro, it produces another C++ source file which contains the meta object code for the classes that contain the Q_OBJECT macro. This generated source file is either #included into the class's source file or compiled and linked with the class's implementation.

In addition to providing the signals and slots mechanism for communication between objects (the main reason for introducing the system), the meta object code provides additional features in QObject:

    * the className() function that returns the class name as a string at runtime, without requiring native runtime type information (RTTI) support through the C++ compiler.
    * the inherits() function that returns whether an object is an instance of a class that inherits a specified class within the QObject inheritance tree.
    * the tr() and trUtf8() functions for string translation as used for internationalization.
    * the setProperty() and property() functions for dynamically setting and getting object properties by name.
    * the metaObject() function that returns the associated meta object for the class.

It is strongly recommend that all subclasses of QObject use the Q_OBJECT macro regardless of whether they actually use signals, slots and properties or not.


Typically moc is not called manually, but automatically by the build system, so it requires no additional effort by the programmer.

Using the Meta Object Compiler

The output produced by the moc must be compiled and linked, just like the other C++ code in your program; otherwise the build will fail in the final link phase. By convention, this is done in one of the following two ways:

Method A: The class declaration is found in a header (.h) file

If the class declaration above is found in the file myclass.h, the moc output should be put in a file called moc_myclass.cpp. This file should then be compiled as usual, resulting in an object file moc_myclass.o (on Unix) or moc_myclass.obj (on Windows). This object should then be included in the list of object files that are linked together in the final building phase of the program.

Method B: The class declaration is found in an implementation (.cpp) file

If the class declaration above is found in the file myclass.cpp, the moc output should be put in a file called myclass.moc. This file should be #included in the implementation file, i.e. myclass.cpp should contain the line

#include "myclass.moc"

at the end. This will cause the moc-generated code to be compiled and linked together with the normal class definition in myclass.cpp, so it is not necessary to compile and link it separately, as in Method A.

Method A is the normal method. Method B can be used in cases where you want the implementation file to be self-contained, or in cases where the Q_OBJECT class is implementation-internal and thus should not be visible in the header file.

Limitations

Multiple inheritance requires QObject to be first

If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject. Also, be sure that only the first inherited class is a QObject.


class SomeClass : public QObject, public OtherClass {

...

};

(This limitation is almost impossible to remove; since the moc does not expand #include or #define, it cannot find out which one of the base classes is a QObject.)

Friend declarations cannot be placed in signals or slots sections

Type macros cannot be used for signal and slot parameters

Nested classes cannot be in the signals or slots sections nor have signals or slots

Constructors cannot be used in signals or slots sections

Properties need to be declared before the public section that contains the respective get and set functions