本文介绍了接口类的纯虚拟信号的连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想连接从接口类派生的一些对象的信号。
连接在 QWidget :: listenToAnimal(AnimalInterface *)中完成。
这不工作,因为 qt_metacall不是'AnimalInterface'的成员静态断言失败:没有Q_OBJECT在类中的信号

I want to connect some object's signals derived from an interface class.The connection is done in QWidget::listenToAnimal(AnimalInterface*).This does not work because qt_metacall is not a member of 'AnimalInterface' and static assertion failed: No Q_OBJECT in the class with the signal.

当然 AnimalInterface 没有Q_OBJECT宏,并且不继承QObject因为它是一个接口...

Of course AnimalInterface does not have the Q_OBJECT macro and does not inherit QObject because it is an interface...

我想通过接口类连接,因为我不想手动重新输入相同的代码 Cat Dog

I want to connect through the interface class because I do not want to manually retype the same code for Cat and for Dog.

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

Is it possible to connect the signal the way I want to? Perhaps with templates? Is this perhaps a lambda-specific problem?

标题:

#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 -derived类型。不需要动态铸造或任何类型的。你只是不想让 listenToAnimal 方法可用于非 - AnimalInterface - 继承类型,即使它们有一个兼容的 madeSound 方法:

Since you know the derived type at compile type, you can connect to the proper, statically-known QObject-derived type. No need for dynamic casting or anything of the sort. You just don't want the listenToAnimal method to be available for non-AnimalInterface-inheriting types, though, even if it they have a compatible madeSound method:

#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



C++03

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

然后可以使用它,而不必拼写出类型 - 到编译器:

You can then use it without having to spell out the type - it's already known to the compiler:

listenToAnimal(dog_);
listenToAnimal(cat_);

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

If the derived type is not known at compile time, you have to dynamically cast to QObject and connect by name, not by method pointer. It will assert at runtime if you've passed in a wrong type - after all, it's not enough for it to be an instance of AnimalInterface, it also needs to be a QObject instance.

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

事实上类型 AnimalInterface 有一个虚拟的 madeSound 方法有点相关 - 它保证派生类实现这种签名的方法。但它不保证该方法是一个信号。所以你应该重新考虑你的设计,问自己:当我不能真正地使用静态类型检查时,我通过使用静态类型系统获得什么?

The fact that the type AnimalInterface has a virtual madeSound method is somewhat relevant - it guarantees that the derived class implements the method with such a signature. It doesn't guarantee that the method is a signal, though. So you should probably rethink your design and ask yourself: "What do I gain by using a static type system when I can't really use it for static type checking"?

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

Most likely you should make any methods that would nominally accept the AnimalInterface*, be parametrized and take a pointer to the concrete class. Modern code generators and linkers will deduplicate such code if type erasure leads to identical machine code.

这篇关于接口类的纯虚拟信号的连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 03:49
查看更多