【问题标题】:Why can not I call virtual function from base class slot Qt为什么我不能从基类插槽 Qt 调用虚函数
【发布时间】:2025-12-01 17:50:01
【问题描述】:

有人可以向我解释为什么在基类插槽中没有调用被覆盖的方法,而是我有一个基本版本的方法:

class ThreadsDispatcher : public QObject
{
   Q_OBJECT
   public:
      explicit ThreadsDispatcher(QObject *parent = 0);
      virtual ~ThreadsDispatcher();
      virtual void OnThreadFinished(IThreadable *pWorker);

   public slots:
      void slotThreadFinished(IThreadable *pWorker);
};

void ThreadsDispatcher::slotThreadFinished(IThreadable *pWorker)
{
   OnThreadFinished(pWorker);
}

void ThreadsDispatcher::OnThreadFinished(IThreadable *pWorker)
{
   qDebug << "Base method, class" << this->metaObject()->className();
}

一个子类:

class CommandsQueueDispatcher : public ThreadsDispatcher
{
    Q_OBJECT
    public:
       explicit CommandsQueueDispatcher(CommandFactory* baseFactory, QObject *parent = 0);
       ~CommandsQueueDispatcher();
       void OnThreadFinished(IThreadable *pWorker);
};

 void CommandsQueueDispatcher::OnThreadFinished(IThreadable *pWorker)
 {
    qDebug << "Subclass method, class" << this->metaObject()->className();
 }

在插槽中调用 OnThreadFinished 后,我得到:

Base method, class ThreadsDispatcher

如果我从另一个方法调用方法 OnThreadFinished,我会正常:

Subclass method, class CommandsQueueDispatcher

我尝试在基类和子类中连接,但没有任何变化:

connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), this, SLOT(slotThreadFinished(IThreadable*)));

但如果我从另一个类连接,即既不是子类也不是基类:

    connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), pWorker, SLOT(slotThreadFinished(IThreadable*)));

在我需要用变量ptr 替换this 的地方,我得到了正常的结果。

我连接的功能:

bool ThreadsDispatcher::AddThread(IThreadable* pThreadWorker)
{
   connect(pThreadWorker, SIGNAL(sigFinished(IThreadable*)), this, SLOT(slotThreadFinished(IThreadable*)));
}

我不直接实例化 ThreadsDispatcher。我创建了 CommandsQueueDispatcher 的非静态对象。

【问题讨论】:

  • 看起来很奇怪。尝试手动重新运行 qmake。此外,如果您使用影子构建(IMO 是一个好主意,并且默认情况下由 Qt Creator 建议),请确保您没有意外地在源目录中完成构建。
  • 我在 qt creator 和 visual studio 2012 下的两台不同的计算机上检查了这个 - 没有效果。看来如果我用这个,那么我还没有访问虚拟成员的表
  • 您能否也显示与插槽进行信号连接的代码?调用哪个函数实现取决于对象的静态类型。
  • 是否有可能在对象构造完成之前调用OnThreadFinished(在CommandsQueueDispatcher 构造函数返回之前)?如果是,那么很可能这是您的问题*.com/a/496450/1387438
  • 没有。我检查断点。两个构造函数都返回,然后调用 OnThreadFinished。此外,如果我将调用 OnThreadFinished 从插槽移动到另一个方法(简单的 C++ 方法),我工作得很好。是signal/slot的qt系统……但是为什么……

标签: c++ qt


【解决方案1】:

故障排除建议(评论太长):

试着把槽改成这样:

void ThreadsDispatcher::OnThreadFinished(IThreadable *pWorker)
{
   qDebug << "Base method, class" << this->metaObject()->className();
}

派生类也一样。看看是什么输出。

如果在调用虚方法与类名一致的意义上输出是“正确的”,那么我怀疑你确实有一个基类对象,而不是派生类对象。

如果输出不匹配,基类虚方法会打印但报告派生类名称,那么我会寻找任何有趣的编译器标志,并尝试使用新项目创建SSCCE,然后也许再在这里询问和/或向 Qt 提交错误报告。

A link 开始阅读 Qt 文档中的相关内容。


故障排除步骤:将基类更改为抽象,方法是在基类中抽象化此方法:

  virtual void OnThreadFinished(IThreadable *pWorker) = 0;

...然后删除方法定义。现在编译器应该告诉你在哪里尝试创建基类的实例。


还有一个建议:Qt 构建基础,例如in this answer。特别是,确保 QObject 子类在 .h 文件中定义,这些文件在 .pro 文件 HEADERS 列表中列出。

【讨论】:

  • 为什么?我在基类中有插槽。我想要,子类不包含插槽。
  • 是的,误读了问题...用新内容编辑了答案。
  • 我不知道为什么,但它是一个基类。
  • 已编辑答案建议将基类抽象化,以便编译器检测您何时尝试实例化它。
  • @AntonCherepanov 又添加了一个建议,尽管这不太可能是这里的问题。如果问题仍然相关,我会尝试为它创建一个 SSCCE。