gpt4 book ai didi

qt - 接口(interface)类纯虚信号的连接

转载 作者:行者123 更新时间:2023-12-02 08:55:49 25 4
gpt4 key购买 nike

我想连接从接口(interface)类派生的某些对象的信号。连接是在QWidget::listenToAnimal(AnimalInterface*)中完成的。这不起作用,因为qt_metacall不是“AnimalInterface”的成员并且静态断言失败:带有信号的类中没有Q_OBJECT

当然AnimalInterface没有Q_OBJECT宏,也没有继承QObject,因为它是一个接口(interface)...

我想通过接口(interface)类进行连接,因为我不想为 CatDog 手动重新输入相同的代码。

是否可以按照我想要的方式连接信号?也许用模板?这可能是 lambda 特定的问题吗?

标题:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class AnimalInterface{
public:
virtual ~AnimalInterface();

virtual void makeSound() = 0;

/*signals*/
virtual void madeSound() = 0;
};
Q_DECLARE_INTERFACE(AnimalInterface,"interface")



class Dog : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};


class Cat : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};



class Widget : public QWidget
{
Q_OBJECT
Cat *cat_;
Dog *dog_;
public:
Widget(QWidget *parent = 0);
~Widget();
void listenToAnimal(AnimalInterface *animal);
};

#endif // WIDGET_H

cpp:

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
: QWidget(parent)
{
dog_ = new Dog;
cat_ = new Cat;

listenToAnimal(dog_);
listenToAnimal(cat_);

dog_->makeSound();
cat_->makeSound();
}

void Widget::listenToAnimal(AnimalInterface *animal)
{
connect(animal, &AnimalInterface::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}

Widget::~Widget()
{

}


void Cat::makeSound()
{
qDebug()<<"Cat says miaow";
emit madeSound();
}
void Dog::makeSound()
{
qDebug()<<"Dog says wuff";
emit madeSound();
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();

return a.exec();
}

最佳答案

由于您知道编译类型的派生类型,因此您可以连接到正确的、静态已知的 QObject 派生类型。不需要动态转换或任何类似的东西。不过,您只是不希望 listenToAnimal 方法可用于非 AnimalInterface 继承类型,即使它们具有兼容的 madeSound > 方法:

C++11

#include <type_traits>

template< class T,
typename =
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value>::type >
void listenToAnimal(T * animal) {
connect(animal, &T::madeSound, this, []{ qDebug() << "animal made sound"; });
}

C++03

template <class T>
void listenToAnimal(T * animal) {
Q_UNUSED(static_cast<AnimalInterface*>(animal));
connect(animal, &T::madeSound, this, &Widget::onAnimalMadeSound);
}

然后您可以使用它,而无需拼写出类型 - 编译器已经知道它:

listenToAnimal(dog_);
listenToAnimal(cat_);

如果派生类型在编译时未知,则必须动态转换为 QObject 并按名称连接,而不是按方法指针连接。如果您传入了错误的类型,它会在运行时断言 - 毕竟,它是 AnimalInterface 的实例还不够,它还需要是 QObject > 实例。

void listenToAnimal(AnimalInterface * animal) {
auto object = dynamic_cast<QObject*>(animal);
Q_ASSERT(object);
connect(object, SIGNAL(madeSound()), this, SLOT(onAnimalMadeSound()));
}

事实上,AnimalInterface 类型具有一个虚拟的 madeSound 方法,这在某种程度上是相关的 - 它保证派生类使用这样的签名来实现该方法。但它并不能保证该方法是一个信号。因此,您可能应该重新考虑您的设计并问自己:“当我无法真正使用静态类型系统进行静态类型检查时,我可以通过使用它获得什么好处”?

很可能您应该创建任何名义上接受 AnimalInterface* 的方法,进行参数化并获取指向具体类的指针。如果类型删除导致相同的机器代码,现代代码生成器和链接器将删除此类代码的重复数据。

关于qt - 接口(interface)类纯虚信号的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39186348/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com