Diferencias entre conexiones basadas en cadenas y en funtores
Qt ofrece dos formas diferentes de escribir conexiones señal-ranura en C++: La sintaxis de conexión basada en cadenas y la sintaxis de conexión basada en funtores. Ambas sintaxis tienen sus pros y sus contras. La siguiente tabla resume sus diferencias.
| Basada en cadenas | Basada en funtores | |
|---|---|---|
| La comprobación de tipos se realiza en... | En tiempo de ejecución | En tiempo de compilación |
| Puede realizar conversiones de tipo implícitas | Y | |
| Puede conectar señales a expresiones lambda | Y | |
| Puede conectar señales a ranuras que tengan más argumentos que la señal (utilizando parámetros por defecto) | Y | |
| Puede conectar funciones C++ a funciones QML | Y |
En las secciones siguientes se explican detalladamente estas diferencias y se muestra cómo utilizar las características exclusivas de cada sintaxis de conexión.
Comprobación de tipos y conversiones de tipos implícitas
Las conexiones basadas en cadenas comprueban los tipos comparando las cadenas en tiempo de ejecución. Este método tiene tres limitaciones:
- Los errores de conexión sólo pueden detectarse después de que el programa haya empezado a ejecutarse.
- No se pueden realizar conversiones implícitas entre señales y ranuras.
- Los typedefs y namespaces no pueden ser resueltos.
Las limitaciones 2 y 3 existen porque el comparador de cadenas no tiene acceso a la información de tipos de C++, por lo que depende de la coincidencia exacta de cadenas.
En cambio, las conexiones basadas en funtores son comprobadas por el compilador. El compilador detecta errores en tiempo de compilación, permite conversiones implícitas entre tipos compatibles y reconoce diferentes nombres del mismo tipo.
Por ejemplo, sólo la sintaxis basada en funtores puede utilizarse para conectar una señal que lleve un int a una ranura que acepte un double. Un QSlider contiene un valor int mientras que un QDoubleSpinBox contiene un valor double. El siguiente fragmento muestra cómo mantenerlos sincronizados:
auto slider = new QSlider(this); auto doubleSpinBox = new QDoubleSpinBox(this); // OK: The compiler can convert an int into a double connect(slider, &QSlider::valueChanged, doubleSpinBox, &QDoubleSpinBox::setValue); // ERROR: The string table doesn't contain conversion information connect(slider, SIGNAL(valueChanged(int)), doubleSpinBox, SLOT(setValue(double)));
El siguiente ejemplo ilustra la falta de resolución de nombres. QAudioInput::stateChanged() se declara con un argumento de tipo "QAudio::State". Por lo tanto, las conexiones basadas en cadenas también deben especificar "QAudio::State", incluso si "State" ya está visible. Este problema no se aplica a las conexiones basadas en funtores, ya que los tipos de argumento no forman parte de la conexión.
auto audioInput = new QAudioInput(QAudioFormat(), this); auto widget = new QWidget(this); // OK connect(audioInput, SIGNAL(stateChanged(QAudio::State)), widget, SLOT(show())); // ERROR: The strings "State" and "QAudio::State" don't match using namespace QAudio; connect(audioInput, SIGNAL(stateChanged(State)), widget, SLOT(show())); // ...
Establecimiento de conexiones con expresiones lambda
La sintaxis de conexión basada en funtores puede conectar señales a expresiones lambda, que son efectivamente ranuras en línea. Esta función no está disponible con la sintaxis basada en cadenas.
En el siguiente ejemplo, la clase TextSender emite una señal textCompleted() que lleva un parámetro QString. Esta es la declaración de la clase:
class TextSender : public QWidget { Q_OBJECT QLineEdit *lineEdit; QPushButton *button; signals: void textCompleted(const QString& text) const; public: TextSender(QWidget *parent = nullptr); };
Esta es la conexión que emite TextSender::textCompleted() cuando el usuario pulsa el botón:
TextSender::TextSender(QWidget *parent) : QWidget(parent) { lineEdit = new QLineEdit(this); button = new QPushButton("Send", this); connect(button, &QPushButton::clicked, [=] { emit textCompleted(lineEdit->text()); }); // ... }
En este ejemplo, la función lambda ha simplificado la conexión a pesar de que QPushButton::clicked() y TextSender::textCompleted() tienen parámetros incompatibles. En cambio, una implementación basada en cadenas requeriría código boilerplate adicional.
Nota: La sintaxis de conexión basada en funtores acepta punteros a todas las funciones, incluidas las funciones independientes y las funciones miembro normales. Sin embargo, en aras de la legibilidad, las señales sólo deben conectarse a ranuras, expresiones lambda y otras señales.
Conexión de objetos C++ a objetos QML
La sintaxis basada en cadenas puede conectar objetos C++ a objetos QML, pero la sintaxis basada en funtores no. Esto se debe a que los tipos QML se resuelven en tiempo de ejecución, por lo que no están disponibles para el compilador de C++.
En el siguiente ejemplo, al hacer clic en el objeto QML, el objeto C++ imprime un mensaje, y viceversa. Este es el tipo QML (en QmlGui.qml):
Rectangle { width: 100; height: 100 signal qmlSignal(string sentMsg) function qmlSlot(receivedMsg) { console.log("QML received: " + receivedMsg) } MouseArea { anchors.fill: parent onClicked: qmlSignal("Hello from QML!") } }
Aquí está la clase C++:
clase CppGui : public QWidget { Q_OBJECT QPushButton *button;signals: void cppSignal(const QVariant& sentMsg) const; slotspúblicos: void cppSlot(const QString& receivedMsg) const { qDebug() << "C++ received:" << receivedMsg; }public: CppGui(QWidget *parent = nullptr) : QWidget(parent) { button = new QPushButton("¡Hazme clic!", this); connect(botón, &QPushButton::clicked, [=] { emite cppSignal("¡Hola desde C++!"); }); } };
Aquí está el código que hace las conexiones señal-ranura:
auto cppObj = new CppGui(this); auto quickWidget = new QQuickWidget(QUrl("QmlGui.qml"), this); auto qmlObj = quickWidget->rootObject(); // Connect QML signal to C++ slot connect(qmlObj, SIGNAL(qmlSignal(QString)), cppObj, SLOT(cppSlot(QString))); // Connect C++ signal to QML slot connect(cppObj, SIGNAL(cppSignal(QVariant)), qmlObj, SLOT(qmlSlot(QVariant)));
Nota: Todas las funciones JavaScript en QML toman parámetros de tipo var, que se corresponde con el tipo QVariant en C++, a menos que utilicen anotaciones de tipo. Véase Invocar métodos QML para más detalles.
Cuando se hace clic en QPushButton, la consola imprime, 'QML recibido: "¡Hola desde C++!"'. Del mismo modo, cuando se hace clic en el Rectángulo, la consola imprime, 'C++ received: "¡Hola desde QML!"'.
Ver Interactuando con Objetos QML desde C++ para otras formas de permitir que objetos C++ interactúen con objetos QML.
Uso de parámetros predeterminados en ranuras para conectarse a señales con menos parámetros
Normalmente, sólo se puede realizar una conexión si la ranura tiene el mismo número de argumentos que la señal (o menos), y si todos los tipos de argumentos son compatibles.
La sintaxis de conexión basada en cadenas ofrece una solución a esta regla: si la ranura tiene parámetros por defecto, éstos pueden omitirse en la señal. Cuando la señal se emite con menos argumentos que la ranura, Qt ejecuta la ranura utilizando los valores predeterminados de los parámetros.
Las conexiones basadas en funtores no soportan esta característica.
Supongamos que hay una clase llamada DemoWidget con una ranura printNumber() que tiene un argumento por defecto:
public slots: void printNumber(int number = 42) { qDebug() << "Lucky number" << number; }
Utilizando una conexión basada en cadenas, DemoWidget::printNumber() puede conectarse a QApplication::aboutToQuit(), aunque esta última no tenga argumentos. La conexión basada en funtores producirá un error de compilación:
DemoWidget::DemoWidget(QWidget *parent) : QWidget(parent) { // OK: printNumber() será llamada con un valor por defecto de 42 connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(printNumber())); // ERROR: El compilador requiere argumentos compatibles connect(qApp, &QCoreApplication::aboutToQuit, this, &DemoWidget::printNumber); }
Para evitar esta limitación con la sintaxis basada en funtores, conecta la señal a una función lambda que llame al slot. Véase la sección anterior, Hacer conexiones con expresiones lambda.
Selección de señales y ranuras sobrecargadas
Con la sintaxis basada en cadenas, los tipos de parámetros se especifican explícitamente. Como resultado, la instancia deseada de una señal o ranura sobrecargada es inequívoca.
En cambio, con la sintaxis basada en funtores, debes especificar explícitamente a qué versión de una señal o ranura sobrecargada deseas conectarte.
Por ejemplo, QLCDNumber tiene tres versiones de la ranura display():
QLCDNumber::display(int)QLCDNumber::display(double)QLCDNumber::display(QString)
Para conectar la versión int a QSlider::valueChanged(), las dos sintaxis son:
auto slider = new QSlider(this); auto lcd = new QLCDNumber(this); // String-based syntax connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int))); // Functor-based syntax connect(slider, &QSlider::valueChanged, lcd, qOverload<int>(&QLCDNumber::display));
Para ver ejemplos completos de conexión a señales y ranuras sobrecargadas utilizando qOverload(), static_cast y lambdas, consulte Conexión a señales y ranuras sobrecargadas.
Véase también qOverload().
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.