web-dev-qa-db-ja.com

GCC C ++リンカーエラー:「vtable for XXX」への未定義の参照、「ClassName :: ClassName()」への未定義の参照

Eclipse-CDTを使用して、Ubuntu x64でC++プロジェクトをセットアップしています。私は基本的にハローワールドをやっていて、商用のサードパーティライブラリにリンクしています。

ライブラリにリンクされたヘッダーファイルを含めましたが、それでもリンカーエラーが発生します。ここには明らかな問題以外に考えられる問題がありますか(例:正しいライブラリにリンクしていることを99%確信しています)。

  1. リンクしている静的ライブラリが64ビットであることを確認する方法はありますか?
  2. ライブラリにクラス(およびメソッド)があることを確認する方法はありますか?

Eclipseは言う:

ビルドターゲット:LinkProblem 
呼び出し:GCC C++リンカー
 g ++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o "LinkProblem" ./ src/LinkProblem.o -lsomelib1 -lpthread -lsomelib2 -lsomelib3 
 ./ src/LinkProblem.o:関数 `main ':
/home/notroot/workspace/LinkProblem/Debug/..内/src/LinkProblem.cpp:17: `SomeClass :: close() '
 ./ src/LinkProblem.o:関数` SomeOtherClass':
/home/notroot/workspaceへの未定義の参照/somelib-3/somelib/include/sql/somefile.h:148: `SomeClass :: SomeClass() '
/home/notroot/workspace/somelib-3/somelib/include/sql /への未定義の参照somefile.h:148: `vtable for SomeOtherClass 'への未定義の参照
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151:` SomeClass ::〜への未定義参照SomeClass() '
 ./ src/LinkProblem.o:関数 `〜SomeOtherClass':
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140:SomeOthの `vtableへの未定義の参照erClass '
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: `SomeClass :: ~~ SomeClass()' 
/home /への未定義の参照notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: `SomeClass ::〜SomeClass() '
 collect2:ldが1つの終了ステータスを返しました
 make :*** [LinkProblem]エラー1 
70
Alex Black

これらのメソッドがライブラリの1つにあると仮定すると、順序付けの問題のように見えます。

ライブラリを実行可能ファイルにリンクする場合、ライブラリは宣言された順序で実行されます。
また、リンカーは、現在未解決の依存関係を解決するために必要なメソッド/関数のみを使用します。後続のライブラリがオブジェクトに本来必要とされなかったメソッド/関数を使用する場合、依存関係が失われます。

使い方:

  • すべてのオブジェクトファイルを取得し、実行可能ファイルに結合します
  • オブジェクトファイル間の依存関係を解決します。
  • For-eachライブラリの順序:
    • 未解決の依存関係をチェックし、libがそれらを解決するかどうかを確認します。
    • その場合、必要な部分を実行可能ファイルにロードします。

例:

オブジェクトに必要なもの:

  • 開いた
  • 閉じる
  • BatchRead
  • BatchWrite

Lib 1は以下を提供します。

  • 開いた
  • 閉じる
  • 読む
  • 書く

Lib 2が提供するもの

  • BatchRead(ただし、lib1:readを使用)
  • BatchWrite(ただし、lib1:writeを使用)

このようにリンクされている場合:

gcc -o plop plop.o -l1 -l2

その後、リンカーは読み取りおよび書き込みシンボルの解決に失敗します。

しかし、次のようにアプリケーションをリンクすると:

gcc -o plop plop.o -l2 -l1

その後、正しくリンクされます。 l2はBatchReadとBatchWriteの依存関係を解決しますが、2つの新しい依存関係(読み取りと書き込み)も追加します。次にl1とリンクすると、4つの依存関係がすべて解決されます。

73
Martin York

このリンカエラーは、(私の経験では)通常、宣言を使用して子クラスの仮想関数をオーバーライドしたが、メソッドの定義を与えていないことを意味します。例えば:

class Base
{
    virtual void f() = 0;
}
class Derived : public Base
{
    void f();
}

しかし、あなたはfの定義を与えていません。クラスを使用すると、リンカーエラーが発生します。通常のリンカエラーと同じように、コンパイラがあなたの言っていることを知っていたのに、リンカは定義を見つけることができなかったからです。メッセージを理解するのが非常に難しいだけです。

166
mgiuca

Qt C++は、クラスを変更してQObjectから継承するように(つまり、シグナル/スロットを使用できるように)クラスを変更すると、このエラーを表示します。 qmake -rを実行すると、mocが呼び出され、この問題が修正されます。

何らかのバージョン管理を介して他のユーザーと作業している場合は、.proファイルに変更を加えます(つまり、空白行を追加/削除します)。他の全員が変更を取得してmakeを実行すると、makeは.proファイルが変更されたことを確認し、qmakeを自動的に実行します。これにより、チームメイトがフラストレーションを繰り返すのを防ぎます。

52
Rick Smith

私にとっての問題はかなりあいまいであることが判明しました。クラスは次のようになりました。

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() { }

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
//-----------------------------------------

//-----------------------------------------
// main.h
class derived : public base {
public:
    virtual int foo() ;
};
//-----------------------------------------

//-----------------------------------------
// main.cpp
int main () {
    derived d;
}
//-----------------------------------------

問題はリンカにあります。私のヘッダーファイルはどこかのライブラリに入れられましたが、すべての仮想関数はクラス宣言で「インライン」で宣言されました。 (まだ)仮想関数を使用するコードがなかったため、コンパイラまたはリンカーは実際の関数本体を配置することを怠りました。また、vtableの作成にも失敗しました。

このクラスから派生したメインコードで、リンカーはクラスを基本クラスとそのvtableに接続しようとしました。しかし、vtableは破棄されていました。

解決策は、次のように、クラス宣言の外側で仮想関数の本体の少なくとも1つを宣言することでした。

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() ;   //-- No longer declared 'inline'

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
base::~base() 
{
}
//-----------------------------------------
15
phord

Qt4の問題に関しては、上記のqmake mocオプションを使用できませんでした。しかし、それはとにかく問題ではありませんでした。クラス定義に次のコードがありました:

class ScreenWidget : public QGLWidget
{
   Q_OBJECT        // must include this if you use Qt signals/slots
...
};

シグナルまたはスロットが定義されていないため、「Q_OBJECT」行を削除する必要がありました。

9
mschachter

このエラーメッセージが表示されました。問題は、ヘッダーファイルで仮想デストラクタを宣言したことですが、仮想関数の本体は実際には実装されていませんでした。

8
lukeinchina

このエラーは、基本クラスの定義なしで仮想関数を単に宣言した場合にも発生します。

例えば:

class Base
{
    virtual void method1(); // throws undefined reference error.

}

上記の宣言を次の宣言に変更すると、正常に機能します。

class Base
{
    virtual void method1()
    {
    }
}
5
user2376546

私の場合、純粋な仮想クラスの1つの関数に= 0を追加するのを忘れたときに問題が発生しました。 = 0が追加されたときに修正されました。上記のフランクと同じです。

class ISettings
{
public: 
    virtual ~ISettings() {};
    virtual void OKFunction() =0;
    virtual void ProblemFunction(); // missing =0   
};

class Settings : ISettings
{
    virtual ~Settings() {};
    void OKFunction();
    void ProblemFunction(); 
};

void Settings::OKFunction()
{
    //stuff
}

void Settings::ProblemFunction()
{
    //stuff
}
4
Lars Persson

私もこの問題に出くわしました。アプリケーションは純粋な仮想インターフェイスクラスを定義し、共有ライブラリを介して提供されるユーザー定義クラスはインターフェイスを実装することになっています。アプリケーションをリンクする際、リンカは、共有ライブラリが基本クラスのvtableとtype_infoを提供しないこと、また他の場所に見つからないことを訴えました。インターフェースのメソッドの1つを純粋な仮想にすることを忘れていました(つまり、宣言の最後に「= 0」を省略しました。非常に初歩的で、リンカーの診断を根本的な原因。

1
frank

純粋な仮想関数を持つ基本クラスがある場合は、基本クラスのコンストラクタとデストラクタに本体があることを確認してください。そうでない場合、リンカは失敗します。

0
sumeet

私は将来の訪問者のためにこれを置きます:

Exceptionオブジェクトの作成時にエラーを受け取った場合、その原因はおそらくwhat()仮想関数の定義の欠如です。

0
Mostafa Talebi

Qtで「hello world」のようなことをしようとすると、このエラーメッセージが表示されました。問題は、qt moc(メタオブジェクトコンパイラ)を正しく実行し、これらのmocで生成されたファイルを正しくコンパイルして含めることでなくなりました。

0
awallin