だから、私は悪名高い恐ろしさを得ています
'vtable ...への未定義の参照.
次のコード(問題のクラスはCGameModuleです)のためのエラーと私は一生懸命問題が何であるか理解することはできません。最初は、仮想機能をボディにするのを忘れることに関連していると思いましたが、私の知る限りでは、すべてがここにあります。継承チェーンは少し長いですが、ここに関連するソースコードがあります。他にどのような情報を提供すればよいかわかりません。
注:コンストラクタはこのエラーが発生しているところです、それはそう思われます。
私のコード:
class CGameModule : public CDasherModule {
public:
CGameModule(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
: CDasherModule(pEventHandler, pSettingsStore, iID, 0, szName)
{
g_pLogger->Log("Inside game module constructor");
m_pInterface = pInterface;
}
virtual ~CGameModule() {};
std::string GetTypedTarget();
std::string GetUntypedTarget();
bool DecorateView(CDasherView *pView) {
//g_pLogger->Log("Decorating the view");
return false;
}
void SetDasherModel(CDasherModel *pModel) { m_pModel = pModel; }
virtual void HandleEvent(Dasher::CEvent *pEvent);
private:
CDasherNode *pLastTypedNode;
CDasherNode *pNextTargetNode;
std::string m_sTargetString;
size_t m_stCurrentStringPos;
CDasherModel *m_pModel;
CDasherInterfaceBase *m_pInterface;
};
継承元...
class CDasherModule;
typedef std::vector<CDasherModule*>::size_type ModuleID_t;
/// \ingroup Core
/// @{
class CDasherModule : public Dasher::CDasherComponent {
public:
CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName);
virtual ModuleID_t GetID();
virtual void SetID(ModuleID_t);
virtual int GetType();
virtual const char *GetName();
virtual bool GetSettings(SModuleSettings **pSettings, int *iCount) {
return false;
};
private:
ModuleID_t m_iID;
int m_iType;
const char *m_szName;
};
どれから継承します....
namespace Dasher {
class CEvent;
class CEventHandler;
class CDasherComponent;
};
/// \ingroup Core
/// @{
class Dasher::CDasherComponent {
public:
CDasherComponent(Dasher::CEventHandler* pEventHandler, CSettingsStore* pSettingsStore);
virtual ~CDasherComponent();
void InsertEvent(Dasher::CEvent * pEvent);
virtual void HandleEvent(Dasher::CEvent * pEvent) {};
bool GetBoolParameter(int iParameter) const;
void SetBoolParameter(int iParameter, bool bValue) const;
long GetLongParameter(int iParameter) const;
void SetLongParameter(int iParameter, long lValue) const;
std::string GetStringParameter(int iParameter) const;
void SetStringParameter(int iParameter, const std::string & sValue) const;
ParameterType GetParameterType(int iParameter) const;
std::string GetParameterName(int iParameter) const;
protected:
Dasher::CEventHandler *m_pEventHandler;
CSettingsStore *m_pSettingsStore;
};
/// @}
#endif
それで、私は問題を考え出しました、そしてそれは悪い論理の組み合わせであり、automake/autotoolsの世界に完全に精通していません。 Makefile.amテンプレートに正しいファイルを追加していましたが、ビルドプロセスのどのステップで実際にmakefileが作成されたのかわかりませんでした。それで、私は私の新しいファイルについて全く知らなかった古いメイクファイルでコンパイルしていました。
回答とGCC FAQへのリンクをありがとう。本当の理由でこの問題が起こるのを避けるために、私はそれを読むことを確実にするでしょう。
GCC FAQ にエントリがあります。
解決策は、純粋ではないすべての仮想メソッドを確実に定義することです。デストラクタは、pure-virtual [class.dtor]/7と宣言されていても定義する必要があります。
それが価値があるもののために、仮想デストラクタでボディを忘れることは以下を生成します:
`vtable for CYourClass 'への未定義の参照。
エラーメッセージは詐欺的なので、私はメモを追加しています。 (これはgccバージョン4.6.3のものでした。)
Qtを使っているなら、qmakeを再実行してみてください。このエラーがウィジェットのクラスにある場合、qmakeはUIクラスのvtableを再生成する必要があることに気付かなかった可能性があります。これで問題は解決しました。
以下の状況によっても、vtableへの未定義の参照が発生する可能性があります。これを試してみてください。
クラスAの内容:
virtual void functionA(parameters)=0;
virtual void functionB(parameters);
クラスBの内容:
Class C Contains:クラスAから派生するクラスCを作成しています。
コンパイルしようとするとエラーとしてクラスCのvtableへの未定義の参照を取得します。
理由:
functionA
は純粋仮想として定義され、その定義はクラスBで提供されています。functionB
は仮想として定義されているので(NOT PURE VIRTUAL)、クラスA自体で定義を検索しようとしますが、クラスBで定義します。
溶液:
virtual void functionB(parameters) =0;
(これは動作確認済みです)私のcppファイルがmakefileにないため、このエラーが発生しました。
私はちょうどあなたがチェックすることができるこのエラーのための別の原因に遭遇しました。
基本クラスは 純粋仮想関数 を次のように定義しました。
virtual int foo(int x = 0);
そしてサブクラスは
int foo(int x) override;
問題は"=0"
が括弧の外側にあるはずだったというタイプミスでした。
virtual int foo(int x) = 0;
それで、あなたがこれよりずっと下にスクロールしている場合、あなたはおそらく答えを見つけることができませんでした - これはチェックするべき他の何かです。
ここにはさまざまな答えの中で起こっている憶測がたくさんあります。以下に、このエラーを再現するためのごくわずかなコードを示し、それがなぜ発生するのかを説明します。
このエラーを再現するための最小限のコード
IBase.hpp
#pragma once
class IBase {
public:
virtual void action() = 0;
};
Derived.hpp
#pragma once
#include "IBase.hpp"
class Derived : public IBase {
public:
Derived(int a);
void action() override;
};
Derived.cpp
#include "Derived.hpp"
Derived::Derived(int a) { }
void Derived::action() {}
myclass.cpp
#include <memory>
#include "Derived.hpp"
class MyClass {
public:
MyClass(std::shared_ptr<Derived> newInstance) : instance(newInstance) {
}
void doSomething() {
instance->action();
}
private:
std::shared_ptr<Derived> instance;
};
int main(int argc, char** argv) {
Derived myInstance(5);
MyClass c(std::make_shared<Derived>(myInstance));
c.doSomething();
return 0;
}
これはGCCを使って次のようにコンパイルできます。
g++ -std=c++11 -o a.out myclass.cpp Derived.cpp
IBase.hppの= 0
を削除すると、エラーを再現できます。私はこのエラーが出ます:
~/.../catkin_ws$ g++ -std=c++11 -o /tmp/m.out /tmp/myclass.cpp /tmp/Derived.cpp
/tmp/cclLscB9.o: In function `IBase::IBase(IBase const&)':
myclass.cpp:(.text._ZN5IBaseC2ERKS_[_ZN5IBaseC5ERKS_]+0x13): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o: In function `IBase::IBase()':
Derived.cpp:(.text._ZN5IBaseC2Ev[_ZN5IBaseC5Ev]+0xf): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o:(.rodata._ZTI7Derived[_ZTI7Derived]+0x10): undefined reference to `typeinfo for IBase'
collect2: error: ld returned 1 exit status
説明
上記のコードでは、コンパイルに成功するために仮想デストラクタ、コンストラクタ、またはその他のファイルを必要としません(ただし、それらを用意する必要があります)。
このエラーを理解する方法は次のとおりです。リンカはIBaseのコンストラクタを探しています。これはDerivedのコンストラクタに必要になります。ただし、DerivedはIBaseのメソッドをオーバーライドするため、IBaseを参照するvtableが添付されています。リンカが「IBase用のvtableへの未定義の参照」と言っている場合、基本的にDerivedはIBaseへのvtable参照を持っていることを意味しますが、IBaseのコンパイル済みオブジェクトコードを見つけることができません。つまり、クラスIBaseには実装なしの宣言があるのです。つまり、IBaseのメソッドは仮想として宣言されていますが、純粋な仮想ORがその定義を提供するものとしてマークするのを忘れていました。
別れのヒント
他のすべてが失敗するならば、このエラーをデバッグする1つの方法はコンパイルする最小のプログラムを構築して、それがあなたが望む状態になるようにそれを変え続けることです。その間に、いつ失敗し始めるかを確認するためにコンパイルを続けます。
ROSとCatkinビルドシステムについてのメモ
Catkinビルドシステムを使用してROSで上記の一連のクラスをコンパイルしている場合は、CMakeLists.txtに次の行が必要です。
add_executable(myclass src/myclass.cpp src/Derived.cpp)
add_dependencies(myclass theseus_myclass_cpp)
target_link_libraries(myclass ${catkin_LIBRARIES})
最初の行は基本的にmyclassという名前の実行ファイルを作りたいと言っています、そしてこれを構築するためのコードはそれに続くファイルを見つけることができます。これらのファイルの1つにmain()があります。 CMakeLists.txtのどこにも.hppファイルを指定する必要はありません。また、Derived.cppをライブラリとして指定する必要はありません。
GNU C++コンパイラは、オブジェクトの仮想関数の定義が複数のコンパイル単位にまたがる場合に備えて、vtable
をどこに置くかを決定しなければなりません(たとえば、オブジェクト仮想関数定義の一部が他の.cppファイルに他の.cppファイルなど。
コンパイラは、最初に宣言された仮想関数が定義されている場所と同じ場所にvtable
を配置することを選択します。
何らかの理由でオブジェクトで宣言された最初の仮想関数の定義を忘れた場合(またはリンク段階でコンパイル済みオブジェクトを誤って追加し忘れた場合)、このエラーが発生します。
副作用として、この特定の仮想関数についてのみ、関数fooが見つからないのような従来のリンカエラーが発生することはありません。
定義を持つオブジェクトファイルへのリンクを忘れた場合、これは非常に簡単に起こります。
さて、これに対する解決策はあなたが定義を見逃しているかもしれないということです。以下の例を参照して、vtableコンパイラエラーを回避してください。
// In the CGameModule.h
class CGameModule
{
public:
CGameModule();
~CGameModule();
virtual void init();
};
// In the CGameModule.cpp
#include "CGameModule.h"
CGameModule::CGameModule()
{
}
CGameModule::~CGameModule()
{
}
void CGameModule::init() // Add the definition
{
}
クロスポストするのではなく。 inheritance を扱っているのであれば、2回目のグーグルヒットは私が逃したものでした。すべての仮想メソッドを定義する必要があります。
といった:
virtual void fooBar() = 0;
詳細はansware vtableと継承へのC++の未定義の参照 を参照してください。それがすでに上で言及されていることに気づいただけで、だれかがそれを助けるかもしれないということを知ってください。
CDasherComponent
がデストラクタの本体を持っていますか?それは絶対にここにはありません - 問題はそれが.ccファイルにあるかどうかです。CDasherModule
はそのデストラクタvirtual
を明示的に定義するべきです。CGameModule
の最後(}
の後)に余分な}; // for the class
があるようです。CGameModule
はCDasherModule
とCDasherComponent
を定義するライブラリに対してリンクされていますか?おそらく、仮想デストラクタを見逃していることが原因です。
virtual ~CDasherModule(){};
これが私にとっては最初の検索結果だったので、チェックするために別のことを追加したいと思いました。仮想関数の定義が実際にクラスにあることを確認してください。私の場合、これがありました。
ヘッダファイル
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
void foo() override;
};
そして私の。ccファイルで:
void foo() {
...
}
これは読むべきです
void B::foo() {
}
たくさんの答えがここにありますが、どれも私の問題が何であるかをカバーしていないようでした。私は以下のものを持っていました:
class I {
virtual void Foo()=0;
};
そして別のファイル(もちろんコンパイルとリンクに含まれています)
class C : public I{
void Foo() {
//bar
}
};
まあこれはうまくいきませんでした、そして私は皆が話しているエラーを得ました。それを解決するために、私はFooの実際の定義をクラス宣言から外す必要がありました。
class C : public I{
void Foo();
};
C::Foo(){
//bar
}
私はC++の第一人者ではないので、なぜこれがより正しいのか説明できませんが、問題は解決しました。
それで私はWindows XPとMinGWコンパイラでQtを使っていました、そしてこのことは私を夢中にさせました。
基本的に、moc_xxx.cppは私が追加されたときでも空に生成されました
Q_OBJECT
機能を仮想的、明示的にしているものすべてを削除してもうまくいかない。最後に1行ずつ削除し始めたところ、次のようになりました。
#ifdef something
ファイルの周り#ifdefがtrueの場合でも、mocファイルは生成されませんでした。
そのため、#ifdefをすべて削除すると問題が解決しました。
これは、WindowsとVS 2013では起きていませんでした。
多分違います。間違いなく~CDasherModule() {}
がありません。
私の場合はQtを使用していて、foo.cpp
(.h
ではない)ファイルにQObject
サブクラスを定義していました。修正は、#include "foo.moc"
の最後にfoo.cpp
を追加することでした。
他のすべてが失敗した場合は、重複を探します。別の投稿で参照を読むまで、コンストラクタとデストラクタへの最初の明示的な参照に誤解されていました。 any 未解決の方法です。私の場合は、パラメータとしてchar * xmlを使用している宣言を、不必要に厄介なconst char * xmlを使用している宣言に置き換えたと思いますが、代わりに新しい宣言を作成して別の宣言を残しました。
このエラーを引き起こすために述べられる多くの可能性があります、そして私はそれらの多くがエラーを引き起こすと確信しています。私の場合、ソースファイルが重複しているため、同じクラスの another 定義がありました。このファイルはコンパイルされましたが、リンクされていなかったので、リンカはそれを見つけることができないことについて不平を言いました。
要約すると、クラスを十分に見つめていて、それが原因で発生している可能性のある構文の問題を確認できない場合は、ファイルが見つからないかファイルが重複しているなどのビルドの問題を探します。
オブジェクトがアーカイブに追加されないというバグが発生したときにオブジェクトにリンクしようとしていた状況で、この種のエラーが発生しました。
LibXYZ.aにintのbioseq.oが含まれているはずですが、そうではないとします。
私はエラーを得ました:
combineseq.cpp:(.text+0xabc): undefined reference to `vtable for bioseq'
これは上記のすべてとは異なる終了です。アーカイブの問題では、この不足しているオブジェクトと呼びます。
次のシナリオでこのエラーが発生しました
ヘッダファイル自体にクラスのメンバ関数の実装を定義した場合を考えてみましょう。このヘッダーファイルはエクスポートされたヘッダーです(つまり、コードベースのcommon/includeに直接コピーされる可能性があります)。これで、メンバ関数の実装を.cppファイルに分離することにしました。実装を.cppに分離/移動した後、ヘッダーファイルにはクラス内のメンバー関数のプロトタイプのみが含まれています。上記の変更後、コードベースをビルドすると、「未定義の 'vtable ...への参照」エラーが発生する可能性があります。
これを修正するには、ビルドする前に、common/includeディレクトリの(変更した)ヘッダファイルを必ず削除してください。また、作成したばかりの新しい.cppファイルから構築された新しい.oファイルを収容/追加するように、メイクファイルを変更してください。これらの手順を実行すると、コンパイラ/リンカは文句を言わなくなります。
既存のソース/ヘッダーのペアに2番目のクラスを追加したときにこのエラーが発生しました。同じ.hファイル内の2つのクラスヘッダー、および同じ.cppファイル内の2つのクラスの関数定義.
私はこれまでうまくいっていましたが、密接に連携することを意図したクラスを使っていましたが、どうやら今回は私には好きではなかったようです。それでも何がわかりませんが、コンパイル単位ごとにそれらを1つのクラスに分割することで問題は解決しました。
失敗した試行
_gui_icondata.h:
#ifndef ICONDATA_H
#define ICONDATA_H
class Data;
class QPixmap;
class IconData
{
public:
explicit IconData();
virtual ~IconData();
virtual void setData(Data* newData);
Data* getData() const;
virtual const QPixmap* getPixmap() const = 0;
void toggleSelected();
void toggleMirror();
virtual void updateSelection() = 0;
virtual void updatePixmap(const QPixmap* pixmap) = 0;
protected:
Data* myData;
};
//--------------------------------------------------------------------------------------------------
#include "_gui_icon.h"
class IconWithData : public Icon, public IconData
{
Q_OBJECT
public:
explicit IconWithData(QWidget* parent);
virtual ~IconWithData();
virtual const QPixmap* getPixmap() const;
virtual void updateSelection();
virtual void updatePixmap(const QPixmap* pixmap);
signals:
public slots:
};
#endif // ICONDATA_H
_gui_icondata.cpp:
#include "_gui_icondata.h"
#include "data.h"
IconData::IconData()
{
myData = 0;
}
IconData::~IconData()
{
if(myData)
{
myData->removeIcon(this);
}
//don't need to clean up any more; this entire object is going away anyway
}
void IconData::setData(Data* newData)
{
if(myData)
{
myData->removeIcon(this);
}
myData = newData;
if(myData)
{
myData->addIcon(this, false);
}
updateSelection();
}
Data* IconData::getData() const
{
return myData;
}
void IconData::toggleSelected()
{
if(!myData)
{
return;
}
myData->setSelected(!myData->getSelected());
updateSelection();
}
void IconData::toggleMirror()
{
if(!myData)
{
return;
}
myData->setMirrored(!myData->getMirrored());
updateSelection();
}
//--------------------------------------------------------------------------------------------------
IconWithData::IconWithData(QWidget* parent) :
Icon(parent), IconData()
{
}
IconWithData::~IconWithData()
{
}
const QPixmap* IconWithData::getPixmap() const
{
return Icon::pixmap();
}
void IconWithData::updateSelection()
{
}
void IconWithData::updatePixmap(const QPixmap* pixmap)
{
Icon::setPixmap(pixmap, true, true);
}
繰り返しになりますが、新しいソース/ヘッダーのペアを追加し、IconWithDataクラスを逐語的に切り取って貼り付けるだけで "うまくいきました"。
vtable
とは何ですか?修正を試みる前に、エラーメッセージが何を言っているかを知ることが役立つ場合があります。高いレベルから始めて、さらに詳細に取り組みます。そうすれば、人々はvtableの理解に慣れたら先にスキップできます。 …そして今、先をスキップしている人々がたくさんいます。 :)こだわりのある人向け:
Vtableは、基本的に polymorphismin C++ の最も一般的な実装です。 vtableが使用される場合、すべてのポリモーフィッククラスにはプログラムのどこかにvtableがあります。クラスの(隠された)static
データメンバーと考えることができます。多態性クラスのすべてのオブジェクトは、その最も派生したクラスのvtableに関連付けられています。この関連付けを確認することにより、プログラムはそのポリモーフィックマジックを実行できます。 重要な注意事項:vtableは実装の詳細です。ほとんどの(すべて?)C++コンパイラはvtableを使用して多態的な動作を実装しますが、C++標準では必須ではありません。私が紹介している詳細は、典型的または合理的なアプローチです。 コンパイラはこれから逸脱することが許可されています!
各ポリモーフィックオブジェクトには、オブジェクトの最も派生したクラスのvtableへの(隠された)ポインターがあります(より複雑な場合は、複数のポインターの可能性があります)。ポインターを見ると、プログラムはオブジェクトの「実際の」タイプが何であるかを知ることができます(構築中を除き、その特殊なケースはスキップしましょう)。たとえば、タイプA
のオブジェクトがA
のvtableを指していない場合、そのオブジェクトは実際にはA
から派生したサブオブジェクトです。
名前「vtable」は「virtual functiontable」に由来します。 (仮想)関数へのポインターを格納するテーブルです。コンパイラーは、表のレイアウト方法についてその規則を選択します。単純なアプローチは、クラス定義内で宣言された順序で仮想関数を実行することです。仮想関数が呼び出されると、プログラムはオブジェクトのvtableへのポインターに従い、目的の関数に関連付けられたエントリに移動し、保存された関数ポインターを使用して正しい関数を呼び出します。この作品を作成するためのさまざまなトリックがありますが、ここではそれらを取り上げません。
vtable
はどこで/いつ生成されますか?Vtableは、コンパイラによって自動的に生成されます(「発行」とも呼ばれます)。コンパイラは、ポリモーフィックなクラス定義を参照するすべての翻訳ユニットでvtableを発行できますが、通常は不必要なやり過ぎです。別の方法( gcc 、およびおそらく他のユーザーが使用)は、単一のソースファイルを選択する方法と同様に、vtableを配置する単一の翻訳単位を選択することです。クラスの静的データメンバーを配置する場所。この選択プロセスが翻訳単位の選択に失敗した場合、vtableは未定義の参照になります。したがって、エラーは明らかに明確ではありません。
同様に、選択プロセスが翻訳単位を選択しても、そのオブジェクトファイルがリンカーに提供されない場合、vtableは未定義の参照になります。残念ながら、この場合のエラーメッセージは、選択プロセスが失敗した場合よりもさらに明確でない場合があります。 (この可能性に言及した回答者に感謝します。そうでなければ忘れていただろう。)
Gccが使用する選択プロセスは、その実装に1つを必要とする各クラスに(単一の)ソースファイルを捧げるという伝統から始める場合に意味があります。そのソースファイルをコンパイルするときにvtableを出力するといいでしょう。それを私たちの目標と呼びましょう。ただし、この伝統に従わない場合でも、選択プロセスは機能する必要があります。したがって、クラス全体の実装を探す代わりに、クラスの特定のメンバーの実装を探しましょう。伝統が守られている場合-そのメンバーが実際に実装されている場合-これは目標を達成します。
Gcc(および潜在的に他のコンパイラー)によって選択されたメンバーは、純粋仮想ではない最初の非インライン仮想関数です。他のメンバー関数の前にコンストラクターとデストラクターを宣言するクラウドの一部である場合、そのデストラクターは選択される可能性が高くなります。 (デストラクタを仮想化することを覚えていましたよね?)例外があります。最も一般的な例外は、デストラクタにインライン定義が提供され、デフォルトのデストラクタが要求されたとき(「= default
」を使用)であると予想されます。
鋭敏な人は、ポリモーフィッククラスがすべての仮想関数のインライン定義を提供できることに気付くかもしれません。それにより、選択プロセスが失敗しませんか?古いコンパイラで実行されます。最新のコンパイラーがこの状況に対処していることを読みましたが、関連するバージョン番号はわかりません。これを調べてみることもできますが、それをコード化するか、コンパイラーが文句を言うのを待つ方が簡単です。
要約すると、「vtableへの未定義参照」エラーの主な原因は3つあります。
これらの原因は、それ自体ではエラーを引き起こすには不十分です。むしろ、これらはエラーを解決するために対処するものです。これらの状況のいずれかを意図的に作成すると、間違いなくこのエラーが発生することを期待しないでください。他の要件があります。これらの状況を解決すると、このエラーが解決されると期待してください。
(OK、この質問が出されたときは3番で十分だったかもしれません。)
先にスキップしている人々を歓迎します! :)
= 0
」ではなく)、定義を提供する(「= default
」ではなく)最初の非インライン仮想関数を見つけます。例
対処方法の詳細はさまざまで、場合によっては別の質問に分岐することもあります( 未定義の参照/未解決の外部シンボルエラーとは何ですか? )。ただし、新しいプログラマを混乱させる可能性のある特定のケースで何をすべきかの例を提供します。
ステップ1では、特定のタイプの機能を持つようにクラスを変更することに言及しています。その機能の説明が頭に浮かぶなら、あなたが私が対処しようとしている状況にあるかもしれません。これは目標を達成する方法であることに留意してください。それが唯一の方法ではなく、特定の状況でより良い方法が簡単に存在する可能性があります。クラスをA
と呼びましょう。デストラクタは(クラス定義で)として宣言されていますか
virtual ~A() = default;
または
virtual ~A() {}
?その場合、2つのステップでデストラクタが必要な関数のタイプに変更されます。まず、その行を
virtual ~A();
次に、プロジェクトの一部であるソースファイル(できればクラス実装のファイル)に次の行を追加します。
A::~A() {}
これにより、(仮想)デストラクタが非インラインになり、コンパイラによって生成されません。 (関数定義にヘッダーコメントを追加するなど、コードの書式設定スタイルに合わせて自由に変更してください。)
次のようなメッセージが表示されることもあります。
SomeClassToTest.Host.o: In function `class1::class1(std::string const&)':
class1.hpp:114: undefined reference to `vtable for class1'
SomeClassToTest.Host.o: In function `class1::~class1()':
class1.hpp:119: undefined reference to `vtable for class1'
collect2: error: ld returned 1 exit status
[link] FAILED: 'g++' '-o' 'stage/tests/SomeClassToTest' 'object/tests/SomeClassToTest.Host.o' 'object/tests/FakeClass1.SomeClassToTest.Host.o'
他のクラスSomeClassのユニットテストをリンクしようとしているときに、クラスFakeClass1の仮想関数を定義するのを忘れた場合。
//class declaration in class1.h
class class1
{
public:
class1()
{
}
virtual ~class1()
{
}
virtual void ForgottenFunc();
};
そして
//class definition in FakeClass1.h
//...
//void ForgottenFunc() {} is missing here
この場合は、もう一度class1の偽物をチェックしてください。あなたはおそらくあなたがあなたの偽のクラスで仮想関数ForgottenFunc
を定義するのを忘れたかもしれないことに気づくでしょう。
少なくとも1つの仮想メソッドを持ち、リンカがファイルを見つけることができないany classのオブジェクトにリンクしようとしたときにもメッセージが表示されることを言及する価値があると思います。例えば:
Foo.hpp:
class Foo
{
public:
virtual void StartFooing();
};
Foo.cpp:
#include "Foo.hpp"
void Foo::StartFooing(){ //fooing }
コンパイル済み:
g++ Foo.cpp -c
そしてmain.cpp:
#include "Foo.hpp"
int main()
{
Foo foo;
}
コンパイルおよびリンク
g++ main.cpp -o main
私たちのお気に入りのエラーを与えます:
/tmp/cclKnW0g.o:Foo 'collect2の関数
main': main.cpp:(.text+0x1a): undefined reference to
vtableに:エラー:ldが1つの終了状況を返しました
これは私の未解決の理由から起こる:
Vtableはコンパイル時にクラスごとに作成されます
リンカはFoo.oにあるvtableにアクセスできません