web-dev-qa-db-ja.com

C ++のvtableへの未定義の参照

私はC++を学んでいます。私は、単一の関数で純粋な仮想クラスのいくつかの実装を定義する演習を実行しようとしています。これらの実装を使用するクラスをリンクするのに問題があります。

==> BasicMath.h <==
#ifndef BASIC_MATH_H
#define BASIC_MATH_H

#include<string>
#include<vector>    

class BasicMath { };


#endif // BASIC_MATH_H

==> Operation.h <==

#ifndef OPERATION
#define OPERATION

#include<string>
#include<vector>    

class Operation {
 public:
  virtual void perform(std::vector<std::string> vec) = 0;
};


#endif // OPERATION

==> Sum.h <==
#ifndef SUM_H
#define SUM_H

#include "Operation.h"

class Sum: public Operation {
 public:
  void perform(std::vector<std::string> vec);
};

#endif // SUM_H

==> BasicMath.cpp <==
#ifndef BASIC_MATH_C
#define BASIC_MATH_C

#include <string>
#include <vector>
#include <iostream>
#include "BasicMath.h"
#include "Sum.h"

int main(int argc, char* argv[]) {
  Sum op;
}

#endif // BASIC_MATH_C

==> Sum.cpp <==
#ifndef SUM_C
#define SUM_C

#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"

void Sum::perform(std::vector<std::string> vec) {
    using namespace std;
    int total = 0;
    cout << "Total: " << total << "\n";
};

#endif // SUM_C

コンパイル:

$ g++ -c Sum.cpp
$ g++ -o BasicMath BasicMath.cpp
/tmp/cc1VXjNl.o:BasicMath.cpp:(.text$_ZN3SumC1Ev[Sum::Sum()]+0x16): undefined reference to `vtable for Sum'
collect2: ld returned 1 exit status

私はここで少なくとも1つのばかげたことをしていると95%確信しています。

this の質問はありますが、問題を解決できませんでした。

16
Ben Fitzgerald

コンパイルリンク行にSum.ofオブジェクトファイルを含めていません(2番目のg ++​​の使用)。

17
Edward Strange

同じ問題が発生しましたが、.cppファイルにデストラクタコードを記述していないことが問題でした。

class.h:

class MyClass {
public:
    MyClass();
    virtual ~MyClass();
};

class.cpp:

MyClass::MyClass() {}

Vtableエラーメッセージが表示され、(空の)デストラクタを実装すると問題が解決しました。

[編集]したがって、修正されたクラスファイルは次のようになります。

MyClass::MyClass() {}
MyClass::~MyClass() {}
26
Till Kolditz

数人の人が、あなたが見た問題の解決策をすでに指摘しています。

少し違うものを追加します。ヘッダーにはヘッダーガードのみが必要です。それらをソースファイルにも含めましたが、実際にはしないでくださいが妥当です。たとえば、sum.cppで本当に必要としない(または必要としない)行をコメントアウトしました。

//#ifndef SUM_C
//#define SUM_C
//
#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"

void Sum::perform(std::vector<std::string> vec) {
    using namespace std;
    int total = 0;
    cout << "Total: " << total << "\n";
};

//#endif // SUM_C

FWIWだけで、performの代わりに、operator()を使用します。

class Operation {
 public:
  virtual void operator()(std::vector<std::string> vec) = 0;
};

そして(明らかに)それはあなたがSumに対してオーバーロードするものでもあります。次のようなものの代わりにそれを使用するには:

Sum op;
op.perform();

あなたは次のようなものを使うでしょう:

Sum op;
op();

これは、実際に関数であるか、「ファンクター」(このようなクラスで、operator()をオーバーロードする)であるかを問わず、関数などの操作を呼び出す他のクラス(標準ライブラリのクラスなど)とクラスを組み合わせる場合に特に便利です。したがって、構文的には関数のように使用できます)。

6
Jerry Coffin

このエラーは、純粋な仮想関数の= 0を忘れた場合にも発生します

エラー:

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

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

int main() {
    Derived d;
    Base *b = &d;
}

エラーなし:

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

これは、= 0がないと、C++はそれが純粋な仮想関数であることを認識せず、それを宣言として扱い、後の定義を期待するためです。

g++ 5.2.1でテスト済み。

通常、このエラーは、純粋な仮想クラスの関数の最後の=0を誤って忘れたときに発生します。

2
doron

Sum.cppなしでBasicMath.cppをコンパイルしているだけです-リンカはSum.cppについて何も知りません。両方を一緒にコンパイルする必要があります。つまり、Sum.cpp BasicMath.cpp一度に実行するか、.cppファイルを個別にコンパイルしてから、両方の.oファイルでg ++を呼び出して実行可能ファイルを作成します。

1
EboMike