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、一般にクラスが宣言される場所であるため、デフォルトでヘッダー ファイルで自動的に実行されるように作られています。mocこのルールはメイクファイルで定義されていることに注意してください。ソース ファイルで手動で実行できます。

qmakeファイルにクラスが含まれていることを通知する必要があります。これを行うには#include "filename.moc"、 の宣言の後に置きCounterます。詳細については、こちら (QtCentre)またはこちら (doc)を参照してください。

qmakeCMake などの別のツールを使用している場合は、moc に強制的に.cppファイルを解析させるルールを指定する必要があります (最も簡単なのは、それらをすべて処理することです)。Qt オブジェクト クラスを含まないファイルmocの場合、空のファイルが生成されます。

ただし、このクラスを「プライベート」にする場合でも、ヘッダーで宣言することをお勧めします (たとえばcounter_private.h)。たとえば、Qt ソースはこのトリックを使用しています。

于 2012-11-28T21:27:09.840 に答える
2

コード ファイルが 1 つしかないようです。デフォルトの方法で Qt プロジェクト ビルドを作成する場合 (qmake && make または QtCreator)、MOC は *.h ファイルのみをスキャンします。1 つの main.cpp にすべてのコードがある場合、MOC はコードを作成しませんが、シグナル/スロットが機能するために必要です。

この特定の例を機能させる最も簡単な方法は、main.cpp の最後に「#include "main.moc"」という行を追加することです。この依存関係は qmake によって検出され、必要な Makefile ターゲットが作成されます。

1 つのクラス - 1 つのヘッダーと 1 つの実装ファイル。

于 2012-11-28T21:26:41.797 に答える
1

それらの moc/uic カスタム ビルド コマンドはヘッダー ファイルで実行されるため、同じソース ファイルに配置された場合ではなく、別のヘッダー/ソース ファイルに配置された場合にコンパイルされます。

于 2012-11-28T21:21:09.863 に答える