【问题标题】:Qt Base Class Function DefinitionsQt 基类函数定义
【发布时间】:2018-12-31 04:30:35
【问题描述】:

我正在使用 gcc 4.8.5 在使用 Qt5 的项目中构建模板库,目标是发送和接收不共享继承层次结构的类型。我想出的一种可能的解决方案是,基类可以简单地定义信号和插槽,而派生类可以提供实现,这很有效。现在,为了编译时优化和运行时性能,如果我在基类中有数百个这样的方法会发生什么?

我无法找到的另一个有效问题似乎是当两个派生类继承同一个对象时在编译期间会发生什么。下面举个例子:

class A{}

class B : A{}

class C : A{}

这种结构在编译时有什么好处吗?此外,Qt 不会为一个类创建 moc,除非它定义了一个信号或槽,所以会有

class A {
    void slot_1();
    //...
    void slot_100();
}

停止编译,这是否有任何运行时开销?我知道 Qt 插槽下面只是一个函数,因此在内存中只创建了一个函数。另外,我知道派生类必须链接 moc_a.o 文件,但我不太确定链接器能够优化到什么程度。

注意:我知道这违反了 SRP 和 OCP,但上面列出了我最大的担忧和障碍。我愿意研究替代示例和解决方法,只要它们不是不必要的复杂且编译时友好。 ISP 也出局了,我根本没有做那么多的多重继承。

【问题讨论】:

  • 我不清楚,你先说没有继承层次结构,然后是派生 QObject 来实现信号/插槽。虚拟函数有一点运行时开销,是的,但除非你在嵌入式廉价系统上工作,否则大多数时候它可以忽略不计。你的确切问题是什么?
  • 我稍后会发布更新,但我的问题是如果我将所有可能的信号和槽添加到基类中,其中每个派生模板类只使用一个信号,我的编译器会处理它还是在编译/链接期间吓坏了。我想出了如何通过 castin 函数来做到这一点
  • @jfhcs 为什么还要问?您可以通过编程方式生成.h 文件和一堆模板实例,然后编译并查看。但这样做的理由是零。感谢 Qt Quick,Qt 完全支持信号和槽的在线生成。

标签: c++ qt class inheritance linker


【解决方案1】:

这是一个 XY 问题:您询问的是解决方案,但您要解决的实际问题是什么?这些类代表什么? “发送和接收类型”是什么意思?至于不共享继承层次结构,有一些简单的方法:一个通用接口可以由一个通用实现的方法提供,如果你在类中添加Q_GADGETQ_OBJECT,你可以自省该方法——假设它们已经不是QObjects。如果您使用QObject,那么您可以通过QMetaObject::invokeMethod 或通过QMetaMethod::invokeOnGadgetQ_GADGET 类型上以编程方式调用方法,并且除了QObject 本身之外确实不需要任何通用接口。

例子:

#include <QtCore>

class Class1 {
  Q_GADGET
public:
  Q_INVOKABLE void foo() { qDebug() << "Class1::foo"; }
};

class Class2 : public QObject {
  Q_OBJECT
public:
  Q_SLOT void foo() { qDebug() << "Class2::foo"; }
};

class Class3 : public QObject {
  Q_OBJECT
public:
  Q_SLOT void bar() { qDebug() << "Class3::bar"; }
};

template <class C> QMetaMethod getMethod(const C& c, const char *signature) {
  auto const &mo = c.staticMetaObject;
  auto const nSignature = QMetaObject::normalizedSignature(signature);
  int index = mo.indexOfMethod(nSignature);
  if (index >= 0)
    return mo.method(index);
  return {};
}

int main() {
  Class1 c1;
  Class2 c2;
  Class3 c3;
  auto foo1 = getMethod(c1, "foo()");
  auto foo2 = getMethod(c2, "foo()");
  auto bar3 = getMethod(c3, "bar()");
  foo1.invokeOnGadget(&c1);
  foo2.invoke(&c2);
  bar3.invoke(&c3);  
}
#include "main.moc"

【讨论】:

  • 如果我说我能够通过将函数的参数转换为连接调用中函数指针的 reinterpret_cast 中的模板类型来实现模板中的信号,你相信我吗?即使按值传递也没有对象切片(我知道 Qt 会复制,如果它不是 const& 而是 shhh)
  • @jfhcs 我不知道你的意思是“模板中的信号”。如果您询问是否可以将信号添加到模板类型:当然可以。但你没有告诉我们你在追求什么。提供您正在使用的“模板”库的示例。它有什么作用?
  • 我找到了一种将信号添加到模板类的方法,而无需在基类中声明每种具体类型的信号。
  • 当然。你真的可以为任何类做到这一点,无论是否模板化。这是因为信号可以完全动态地生成。这就是使 QML 成为可能的原因。这也是 PyQt 成为可能的原因。实际上所有其他 Qt 到脚本语言的桥梁也是如此。见private/qmetaobjectbuilder_p.h
  • 你也可以在编译时使用Verdigris来做。
猜你喜欢
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
  • 2020-03-04
  • 1970-01-01
相关资源
最近更新 更多