QT Core Mechanism 1: Metasystem

written in front

This article is basically an understanding of the translation of some chapters of the official Qt documentation. The reason for translating these chapters is that I think these are the core things in Qt. The process of translation is the process of forcing myself to read them carefully. I will copy the original text word by word, but translate the key points according to my own understanding. After all, my purpose is to understand them and organize them in a way that I can use flexibly, rather than mechanically transforming them from one to the other. Language changes into another language. The original content of the official documents involved mainly includes the following chapters:

  1. The Meta-Object System meta-object system
  2. The Property System property system
  3. Signals & Slots Signals and Slots

It is agreed here that the translation of the original text uses normal fonts, and personal understanding uses italic fonts.

It is divided into three articles in total. This article is the translation of The Meta-Object System .

Links to all three translations:

QT Core Mechanism 1: Metasystem_lczdk's Blog-CSDN Blog

QT core mechanism 2: attribute system_lczdk's blog-CSDN blog

QT Core Mechanism 3: Signals and Slots - Programmer Sought

meta object system

General introduction

Qt's meta-object system provides signals & slots for inter-object communication, runtime type information, and a dynamic property system.

The entire meta-object system is built on three things:

  1. The QObject class provides a base class for all objects. As long as you inherit this class, the created object can use the meta-object system.
  2. When declaring a class, place the Q_OBJECT macro in the private area of ​​the class to enable meta-object features in the class, such as dynamic properties, signals, and slots. In general practical use, we always place the Q_OBJECT macro at the beginning of the class declaration. In addition, our class also needs to inherit the QObject class .
  3. Meta-Object Compiler (Meta-Object Compiler, abbreviated as moc), provides the necessary code for each QObject subclass to implement meta-object features. We can think that Qt has made some extensions to C++, and moc is responsible for translating these extended grammars into native C++ grammars, and then handing them over to the C++ compiler for compilation .

The moc tool reads c++ source files. If it finds one or more class declarations containing the Q_OBJECT macro, it generates another C++ source file containing the meta-object code for each class. The generated source files are either #included into the class's source file, or (more commonly) compiled and linked to the class's implementation.

Meta-object manipulation and information acquisition

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

  • QObject::metaObject(), this method can be used to get the meta object bound in the class.
  • QMetaObject::className(), this method can get the name of the class (in string form) at runtime without the native runtime type information (RTTI) support provided by the c++ compiler.
  • QObject::inherits(), this method is used to determine whether an object is an instance of a certain class. To use this method, this class or its parent class must inherit from the QObect class.
  • The two methods QObject::tr() and QObject::trUtf8() are used to translate strings for internationalization. It is probably used to set multiple languages ​​​​for the application, and I have never used it.
  • QObject::setProperty() and QObject::property() dynamically set and get properties by name.
  • QMetaObject::newInstance() is used to construct a new QObject instance object.

dynamic type conversion

Dynamic type conversions can also be performed on the QObject class using qobject_cast(). The qobject_cast() function behaves like standard c++ dynamic_cast() with the advantage that it does not require RTTI support and works across dynamic library boundaries. It attempts to cast its argument to the pointer type specified in angle brackets, returning a non-zero pointer if the object is of the correct type (determined at runtime), or 0 if the object is of an incompatible type.

For example, let's assume that MyWidget inherits from QWidget and declare it with the Q_OBJECT macro:

QObject *obj = new MyWidget;

The obj variable of type QObject* actually refers to a MyWidget object, so we can cast it appropriately:

QWidget *widget = qobject_cast<QWidget*>(obj);

The conversion from QObject to QWidget is successful because the object is actually a MyWidget, which is a subclass of QWidget. Since we know obj is a MyWidget, we can also cast it to MyWidget*:

// 以下两种都可以
MyWidget *myWidget = qobject_cast<MyWidget*>(obj);
MyWidget *myWidget = qobject_cast<MyWidget*>(widget);

The cast to MyWidget is successful because qobject_cast() does not distinguish between built-in Qt types and custom types. That is to say, as long as it inherits the QObject class and uses the Q_OBJECT macro definition in the class declaration, even a custom class can use this mechanism for type conversion. This thing can be compared to the dynamic type conversion realized by the pointer of void type in C language, but this mechanism of Qt is much safer than the pointer of C language due to the existence of type checking .

// 以下操作会失败,返回0
QLabel *label = qobject_cast<QLabel*>(obj);

Attempts to convert the obj variable to the QLabel type will fail, and the label variable will be assigned a value of 0. Because although both QLabel and MyWidget inherit QObject, there is no inheritance relationship between QLabel and MyWidget. MyWidget can only be converted to its parent class, such as QWidget or QObject, or converted back from its parent class .

Of course, with this feature we do different things at runtime based on the type of the object. As follows:

// 针对obj对象的不同类型设置不同的文本显示
if (QLabel *label = qobject_cast<QLabel *>(obj)) 
{
    
    
	label->setText(tr("Ping"));
} 
else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) 
{
    
    
	button->setText(tr("Pong!"));
}

While it is possible to use QObject as a base class without the Q_OBJECT macro and meta-object code, signals and slots, as well as other features described here, are not available without the Q_OBJECT macro. From the point of view of the meta-object system, a QObject subclass without a meta-code is equivalent to its closest ancestor with a meta-object code. This means that, for example, QMetaObject::className() will not return the actual name of your class, but the class name of this ancestor.

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

Supongo que te gusta

Origin blog.csdn.net/lczdk/article/details/125012017
Recomendado
Clasificación