Preface
thisconnect
Functions are like the word "fen" in the programming world, with ever-changing changes and unique advantages. As for us programmers, just like Kong Yiji, although sometimes they find these changes a little funny and even a bit troublesome, after all, they have to learn and use them obediently. After all, this is a "must-have skill" in programming. Everyone has their own habits and characteristics when writing connect. We need to go into it in depth.
In Qt,connect
Functions are used to connect signals to slots so that slot functions are automatically called when signals are transmitted. Qt offers several different types ofconnect
The writing method and the way to define slot functions have their own characteristics and applicable scenarios.
1. Traditional slot function writing
In traditional Qt projects, slot functions are usually used in class header filesslots:
A special member function declared by a keyword. For example:
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // Declare slot functions using slots keyword void onCalculateClicked(); // ... Other members and slot functions ...};
Then implement this slot function in the source file:
void MainWindow::onCalculateClicked() { // Implementation of slot functions}
When using this writing method,conect
Functions are usually called like this:
connect(pbt, SIGNAL(clicked()), this, SLOT(onCalculateClicked()));
The one used here isSIGNAL()
andSLOT() macro
to convert signals and slots into identifiers in string form.
2. Connect writing using function pointer (5.0)
In 5.0 and subsequent Qt versions, it is recommended to use function pointersconnect
Written because it provides better type checking and compile-time error detection. This writing method does not require useslots:
Keyword orSIGNAL()
/SLOT()
Macro, instead, use function pointers directly. For example:
connect(pbt, &QPushButton::clicked, this, &MainWindow::onCalculateClicked);
In this way of writing,&QPushButton::clicked
It's a signalclicked
function pointer,&MainWindow::onCalculateClicked
is a function pointer to the slot function. The compiler checks whether these pointers match at compile time. The advantages of this writing are as follows:
Type safety:
Function pointerconnect
Writing provides compile-time type checking. This means that if the signal and slot's function signature do not match, or the specified function does not exist, the compiler will immediately give an error message. This greatly reduces the possibility of runtime errors, as all connections are verified at compile time.Easy to read and maintain:
Using function pointers makes the code more intuitive and easy to understand. You can directly see which signal is connected to which slot, without indirect representation via strings. This helps with code maintenance and debugging, as you can more easily track the connection relationship between signals and slots.Automatically handle function overloading:
When there are multiple overloaded signals or slot functions, the correct overloaded version can be automatically selected using the function pointer. TraditionalSIGNAL()
andSLOT()
Macros may encounter problems when dealing with overloaded functions because they rely on string representations of function names and cannot distinguish overloaded functions. The function pointer contains the complete signature of the function, so you can accurately select the desired function.Improve performance:
Although the performance difference may not be very significant, the function pointerconnect
It may be written slightly faster than a macro using strings. This is because function pointers can be parsed and concatenated directly at compile time without string comparison and searching at runtime.Compatible with modern C++ standards:
With the continuous development of C++ standards, the use of function pointersconnect
The writing style is more in line with the programming style of modern C++. It takes advantage of features in C++11 and later, such as lambda expressions and smart pointers, allowing Qt's code to be better integrated with these modern features.Reduce the use of macros:
Reducing the use of macros can reduce the complexity of the code and potential errors. Macros are often the source of problems that are difficult to debug in C++ because they are unfolded in the preprocessing phase, rather than type checking during the compilation phase. Using function pointers can avoid these problems.
3. Lambda expression as slot function (C++11)
After C++11, in addition to traditional slot functions and function pointers, Qt also supports the use of Lambda expressions as slot functions. This writing is very flexible because it allows you toconnect
The code for the slot function is written directly in the call, without defining additional member functions in the class. For example:
connect(pbt, &QPushButton::clicked, this, [this]() { // Implementation of Lambda expression as slot function bool isOK; double r = lEdit->text().toDouble(&isOK); if (isOK && r >= 0) { lab2->setText(QString::number(AreaCircal(r))); } else { lab2->setText("Please enter a legal radius!"); } });
The advantages of this writing are as follows:
Capture or reference capture to control the life cycle and scope of these variables.
Flexibility and dynamics:
Lambda expressions provide a flexible way to define the behavior of slot functions. You canconnect
Write Lambda expressions directly in the call without declaring slot functions in the class in advance. This allows you to dynamically define the behavior of slot functions at runtime as needed.Reduce the code volume:
Using Lambda expressions as slot functions can reduce the amount of code that needs to be written. You don't need to declare a member function for each slot function, which not only reduces the amount of code, but also makes the code more compact and manageable.Type safety:
Using Lambda expressions as slot functions provides better type safety compared to traditional string macros. The compiler checks at compile time whether the type of the Lambda expression matches the parameter type of the signal, thus avoiding runtime errors.
In addition to the first traditional writing method, the two or three more popular writing methods are compared and analyzed as follows:
characteristic | Lambda Expressions | Function pointer |
---|---|---|
Introduce time | C++11 | Early C++ versions, Qt5.0 |
How to define | Anonymous functions are defined directly in the code | The function needs to be declared and defined explicitly, and then point to the function through the function pointer |
Syntax conciseness | Concise, directly defined at the call | Relatively cumbersome, requiring additional function declarations and definitions |
Type inference | Supported, the compiler can infer types based on context | Not supported, need to explicitly specify the function return type and parameter type |
Capture external variables | Can capture variables in external scope | Unable to directly capture external variables, only access function parameters |
Execution Environment | Execute in new stack frames with independent call environment and stack space | Point to existing functions and do not have independent stack space |
flexibility | Suitable for simple, single-line expressions, easy to implement functional closures at the time and place required | Suitable for calling already defined functions, supporting dynamic binding and callback functions |
Code reusability | Usually used for one-time or short-term function definitions, with less reusable code | The same function can be called at different locations through function pointers, and the code is highly reusable. |
Type safety | Type-safe, compiler checks function signature | Low type safety, easy to cause type mismatch |
performance | Performance losses after optimization of modern compilers are negligible, but in some cases it can lead to slight overhead | Usually the performance overhead is low, but indirect calls may bring some additional overhead |
Use scenarios | Suitable for scenarios where simple anonymous functions need to be defined, such as sorting and filtering in STL algorithms | Suitable for scenarios where different functions are required to dynamically call different functions or implement callback functions, such as event processing, plug-in systems, etc. |
A summary of the characteristics and differences of the above three methods:
- Traditional slot functions: Easy to read and maintain, especially when the slot function logic is complex or requires multiple reuse. However, they increase the complexity of the class because slot functions need to be declared in the header file.
- Connect function pointer: Provides better type safety and reduces the possibility of runtime errors. It is the recommended way of modern Qt programming.
- Lambda Expressions: Very flexible, suitable for simple, one-time slot function logic. However, if Lambda expressions are too complex, it may reduce the readability of the code.
4. Use QOverload to select the writing method of overloaded signals (Qt5.7)
useQOverload
The writing method of selecting overloaded signals was also introduced in Qt5, which has significant advantages in the Qt framework and is suitable for specific scenarios. For example, when using comboBox, sometimes indexes are used, and sometimes strings are used as parameters:
QComboBox *comboBox = new QComboBox; QLabel *label = new QLabel; label->setText("Initial Text"); // Add some options to the combo box comboBox->addItem("Option 1"); comboBox->addItem("Option 2"); comboBox->addItem("Option 3"); // Use QOverload to connect the overloaded signal to different slots QObject::connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [](int index){ qDebug() << "Current index changes:" << index; }); QObject::connect(comboBox, QOverload<const QString&>::of(&QComboBox::currentIndexChanged), [](const QString &text){ qDebug() << "Current text changes:" << text; });
In this example,currentIndexChanged
The signal is overloaded twice: one accepts an integer parameter (representing the index of the currently selected item) and one accepts a string parameter (representing the text of the currently selected item). We useQOverload
The template class specifies which overloaded version of the signal we want to connect to. We then use a lambda expression to define the code that is executed when the signal is emitted.QOverload
is a template class introduced in Qt 5.7 and later, which is used to provide type safety when connecting reloaded signals. In versions prior to Qt 5.7, you may need to usestatic_cast
or function pointers to implement the same function, but doing so is usually less secure and error-prone.
Specific advantages:
-
Type safety:
- use
QOverload
It is ensured that when connecting signals and slots, the parameter types of signals and slots exactly match. This helps catch potential errors at compile time and improves code stability.
- use
-
Clear and clear:
- The code is clearer and easier to understand by explicitly specifying the version of the overloaded signal to be connected. Other developers can see the correspondence between signals and slots at a glance, reducing misunderstandings and errors.
-
flexibility:
-
QOverload
Allows developers to select the signal version that best suits the current needs to connect when there are multiple reloaded versions of the signal. This increases the flexibility of the code, allowing it to adapt to different scenarios and needs.
-
-
Avoid ambiguity:
- In no
QOverload
Previously, if there were multiple overloaded versions of the signal, developers would need to specify the version of the signal to be connected through other ways (such as function pointer conversion), which could introduce ambiguity and errors. andQOverload
A direct and clear way to avoid these problems is provided.
- In no
This writing method is used when there are multiple overloaded versions of the signal,QOverload
The template class explicitly specifies which overloaded version of the signal to be connected. For example, comboBox::currentIndexChanged
The signal may have multiple reloaded versions, and by usingQOverload<int> or QOverload<const QString&>
Identify it and then process it. Adapt to scenarios:
-
There are multiple reloaded versions of the signal:
- When there are multiple overloaded versions of signals in the class, use
QOverload
You can explicitly specify the overloaded signal version to connect to, thereby avoiding connection errors or ambiguity.
- When there are multiple overloaded versions of signals in the class, use
-
Type-safe signal slot connection is required:
- In projects with high type safety requirements, use
QOverload
It can ensure that the parameter types of signals and slots are exactly matched, reducing the possibility of runtime errors.
- In projects with high type safety requirements, use
-
Complex GUI applications:
- In complex GUI applications, the connection between signals and slots can become very complex. use
QOverload
It can make the code clearer and easier to understand, and facilitate maintenance and management.
- In complex GUI applications, the connection between signals and slots can become very complex. use
-
Requires flexibility in handling different parameter types:
- In some scenarios, it may be necessary to process signals based on different parameter types. use
QOverload
Signal versions of different parameter types can be easily selected to connect to meet these needs.
- In some scenarios, it may be necessary to process signals based on different parameter types. use
Having written this, I feel that it is a bit similar to the several ways of writing the word "Jade" mentioned by Kong Yiji. Here is the Qtconnect
Functions are simply the word "fen" in the programming world! If Kong Yiji travels to the programming world, he will seeconnect
I was afraid that my beard would be shaken off because of my smile, and I had to mutter in my heart: "The connect of this signal slot has so many changes, which is amazing!"
Imagine, weconnect
Functions are simply "versatile experts" in programming. They can not only relate to old function pointers, but also secretly send misunderstandings to the trendy Lambda expressions, and also have some ambiguous relationships with the signal mapping mechanism. Isn't this? Just like Kong Yiji studied several ways of writing the word "wind", we programmers also have to think about it.connect
Several poses -_-||b
When choosing which writing method, it should be determined based on the specific needs and code style. For complex slot function logic, traditional slot function may be more suitable; for simple logic or temporary connections, Lambda expressions may be more convenient; and for function pointersconnect
It is usually a compromise choice, safe and easy to use.
Summarize
This is the end of this article about several ways to write connect in Qt C++. For more related content on the writing of connect in Qt C++, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!