5

我有一个带有多个使用信号和插槽的类的 Qt 应用程序,它编译得很好。但是,当我在主 CPP (main.cpp) 文件中创建自定义类时,会出现链接器错误。

这是我使用的代码:

class Counter : public QObject
{
    Q_OBJECT

public:
    Counter() { m_value = 0; }

    int value() const { return m_value; }

public slots:
    void setValue(int value)
    {
     if(value!=m_value)
     {
         m_value = value;
         qDebug() << "Value " << value;
         emit valueChanged(value);
     }
    }

signals:
    void valueChanged(int newValue);

private:
    int m_value;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    Counter a, b;
    QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));

    a.setValue(12);     // a.value() == 12, b.value() == 12
    b.setValue(48);     // a.value() == 12, b.value() == 48

    QTimer::singleShot(0, &app, SLOT(quit()));

    return app.exec();
}

以下是错误:

Error   4   error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall Counter::metaObject(void)const " (?metaObject@Counter@@UBEPBUQMetaObject@@XZ)  
Error   5   error LNK2001: unresolved external symbol "public: virtual void * __thiscall Counter::qt_metacast(char const *)" (?qt_metacast@Counter@@UAEPAXPBD@Z)
Error   6   error LNK2001: unresolved external symbol "public: virtual int __thiscall Counter::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@Counter@@UAEHW4Call@QMetaObject@@HPAPAX@Z)   
Error   7   error LNK2019: unresolved external symbol "protected: void __thiscall Counter::valueChanged(int)" (?valueChanged@Counter@@IAEXH@Z) referenced in function "public: void __thiscall Counter::setValue(int)" (?setValue@Counter@@QAEXH@Z)

当我将计数器放在单独的头文件中时,不会发生此链接器错误。这种行为的原因是什么?

4

3 回答 3

6

我假设你正在使用qmake.

moc默认情况下,它会自动在头文件上运行,因为这是一般声明类的地方。请注意,此规则是在 makefile 中定义的,您可以moc在源文件上手动运行。

您必须通知qmake该文件包含一个类。为此,#include "filename.moc"请将Counter. 您可以在此处 (QtCentre)此处 (doc)查看更多详细信息。

如果您使用的是其他工具qmake,例如 CMake,则必须指定一个规则来强制 moc 解析.cpp文件(最简单的是处理所有文件)。对于不包含 Qt 对象类的文件,moc将生成一个空文件。

然而,即使这个类是“私有的”,我建议你在标题中声明它(例如counter_private.h)。例如,Qt 源码就使用了这个技巧。

于 2012-11-28T21:27:09.840 回答
2

看起来您只有一个代码文件。如果您使用默认方式创建 Qt 项目构建(qmake && make 或 QtCreator),MOC 仅扫描 *.h 文件。如果您将所有代码放在一个 main.cpp 中,MOC 将不会创建任何代码,但这是 Signal/Slots 工作所必需的。

使这个特定示例工作的最简单方法是在 main.cpp 的末尾添加一行“#include “main.moc””。qmake 将检测到此依赖关系,并创建所需的 Makefile 目标。

最可爱的方法是干净的:一个类 - 一个头文件和一个实现文件。

于 2012-11-28T21:26:41.797 回答
1

他们 moc/uic 自定义构建命令是在头文件上完成的,所以当放在单独的头文件/源文件中而不是放在同一个源文件中时它会编译

于 2012-11-28T21:21:09.863 回答