これは私のヘッダーです:
#ifndef BARELYSOCKET_H
#define BARELYSOCKET_H
#include <QObject>
//! The First Draw of the BarelySocket!
class BarelySocket: public QObject
{
Q_OBJECT
public:
BarelySocket();
public slots:
void sendMessage(Message aMessage);
signals:
void reciveMessage(Message aMessage);
private:
// QVector<Message> reciveMessages;
};
#endif // BARELYSOCKET_H
これは私のクラスです:
#include <QTGui>
#include <QObject>
#include "type.h"
#include "client.h"
#include "server.h"
#include "barelysocket.h"
BarelySocket::BarelySocket()
{
//this->reciveMessages.clear();
qDebug("BarelySocket::BarelySocket()");
}
void BarelySocket::sendMessage(Message aMessage)
{
}
void BarelySocket::reciveMessage(Message aMessage)
{
}
リンカーエラーが表示されます。
undefined reference to 'vtable for BarelySocket'
Message
は複雑なstruct
ですが、int
を使用しても問題は修正されませんでした。Q_OBJECTマクロに新しい呼び出しを追加するたびに、qmakeを再度実行する必要があります。参照しているvtablesの問題は、それに直接関連しています。
Qmakeを実行するだけで、コードに他の問題がないと仮定して準備ができているはずです。
私は問題を解決する多くの方法を見てきましたが、なぜそれが起こるかについての説明はありませんので、ここに行きます。
コンパイラは、仮想関数(直接宣言または継承)を持つクラスを見つけると、そのクラスのvtableを生成する必要があります。クラスは一般にヘッダーで定義されるため(したがって、複数の翻訳単位で表示されるため)、問題はvtableをどこに配置するかです。
一般に、問題は、クラスが定義されているすべてのTUでvtableを生成し、リンカーに重複を排除させることで解決できます。クラス定義はすべての発生で同じである必要があるためODRによってこれは安全ですが、コンパイルが遅くなり、オブジェクトファイルが膨張し、リンカがより多くの作業を行う必要があります。
したがって、最適化として、可能な場合、コンパイラは特定のTUを選択してvtableを配置します。一般的なC++ ABIでは、このTUはクラスのキー関数が実装されているもの。キー関数は、クラスで宣言されているが定義されていない最初の仮想メンバー関数です。
Qtクラスの場合、通常はQ_OBJECTマクロで始まり、このマクロには宣言が含まれます
virtual const QMetaObject *metaObject() const;
これはマクロ内の最初の仮想関数であるため、通常はクラスの最初の仮想関数、したがってそのキー関数になります。したがって、コンパイラはほとんどのTUでvtableを発行せず、metaObject
を実装するTUのみを発行します。そして、この関数の実装は、ヘッダーを処理するときにmoc
によって自動的に書き込まれます。したがって、ヘッダーをmoc
処理して新しい.cppファイルを生成し、その.cppファイルをコンパイルに含める必要があります。
したがって、QObject
派生クラスを定義する新しいヘッダーがある場合は、qmake
を再実行して、新しいヘッダーでmoc
を実行してコンパイルするようにメイクファイルを更新する必要があります。結果の.cppファイル。
何かをテストするために作成した小さな「main.cpp」ファイル内に小さなクラスを作成した後、このエラーに遭遇しました。
1時間ほどかけて、最終的にそのクラスをmain.cppからスタンドアロンhppファイルに移動し、.pro(プロジェクト)ファイルを更新して、プロジェクトを完全に正常にビルドしました。ここでは問題ではなかったかもしれませんが、とにかく有用な情報になると考えました。
経験から:多くの場合、qmake && make clean && makeは役立ちます。私は個人的には、変更の発見/キャッシュ効果/ xxxxxが何であれわからないことを認識しています。理由を言うことはできませんが、この種のエラーが発生したときに最初に行うことです。
ところで。 > recive <にタイプミスがあります
コンストラクター(初期化子リスト内)でQObjectコンストラクターを呼び出すのを忘れました。 (ただし、エラーは解決しません)
私にとっては、ビルドログからmocが呼び出されていないことに気付きました。 Clean Allは役に立ちませんでした。そこで.pro.userを削除し、IDEを再起動しました。
QOBjectからクラスを派生する(およびQ_OBJECTマクロを使用する)場合、コンストラクタークラスとデストラクタクラスの両方を明確に定義および作成することを忘れないでください。コンパイラのデフォルトのコンストラクタ/デストラクタを使用するだけでは不十分です。 qmakeのクリーニング/実行(およびmoc_ファイルの消去)に関するアドバイスは引き続き適用されます。これは私の同様の問題を修正しました。
シグナルに実装を含めることはできません(これはQtによって生成されます)。 .cppファイルからreciveMessage
実装を削除します。これで問題が解決する場合があります。
私が見た他のこと:BarelySocket
クラスはQObjectを継承するため、破壊時の問題を回避するために仮想デストラクタが必要です。これは、他のクラスから継承するすべてのクラスに対して実行する必要があります。
私はこのエラー時間に苦労しました。 .cppファイルと.hファイルを別のフォルダー(!!)に入れることで解決しました。次に、.proファイルにフォルダーを追加しました:INCLUDEPATH + = $$ {_ PRO_FILE_PWD _} /../ MyClasses/CMyClassWidget
そして、.cppおよび.hファイルを追加しました。やっと動作します。
私はあなたがこれを見るかもしれない別の理由を見つけました-qmake
はあなたがこのエラーを得るかもしれない非標準的な方法でそれらを修正した場合あなたのクラスファイルを解析するので。私の場合、QDialogから継承したカスタムダイアログがありましたが、WindowsまたはOSXではなく、Linux用にビルドするときにコンパイルして実行するだけでした。私はただ#ifdef __linux__
クラスはコンパイルされませんでしたが、Linuxでは__linux__
は、qmake
をスローしていると定義されました。