6

ツール wsdl2h および soapcpp2 を使用した gsoap は、以下を含む soapStub.h ファイルを提供してくれました。

class SOAP_CMAC ns2__SOAPKunden
{
  public:
    std::string *adresszusatz; 
    // ...
  public:
    virtual int soap_type() const { return 7; }
    // ...
    ns2__SOAPKunden() : adresszusatz(NULL), x(NULL) { }   // left out all member init.
    virtual ~ns2__SOAPKunden() { }
};

このクラスを使用して、Informix DB からのデータをオブジェクトに取り込む小さなアプリから始めます。

しかし、正常にコンパイルするには、すべての仮想のものを残す必要があります-このエラーとサブクラスでの仮想メンバーの使用に関する多くの投稿を見つけました-そうしないと、

main.o: In function `ns2__SOAPKunden::ns2__SOAPKunden()':
main.cpp:(.text._ZN15ns2__SOAPKundenC1Ev[ns2__SOAPKunden::ns2__SOAPKunden()]+0xf): undefined reference to `vtable for ns2__SOAPKunden'
main.o: In function `ns2__SOAPKunden::~ns2__SOAPKunden()':
main.cpp:(.text._ZN15ns2__SOAPKundenD1Ev[ns2__SOAPKunden::~ns2__SOAPKunden()]+0x13): undefined reference to `vtable for ns2__SOAPKunden'
collect2: ld returned 1 exit status

何年にもわたるスクリプト作成の後で、C++ コードを理解するのが非常に難しいことだけは認めます... 次に何を試すべきかアドバイスを求めたいと思います。私のクラスは派生クラスではありません。たとえば、不思議に思うのはそのためです。

4

2 に答える 2

14

このエラーは、仮想テーブルが最終バイナリ (実行可能ファイルまたはライブラリ) で正しくコンパイル/リンクされていないことを意味します。このエラーが発生する一般的な状況は 2 つあります。

  • 仮想テーブル定義を含むオブジェクト ファイルをリンクしていません。つまり、 にコンパイルsoapStub.cppしましsoapStub.oたが、そのバイナリをリンカー コマンド ラインに追加していません。
  • コンパイラはどこにも仮想テーブルを生成していないため、すべてのオブジェクト ファイルを含めても、仮想テーブルは含まれません。

2 番目のケースは、経験の浅い開発者にとって最も識別が難しく、ヘッダーで定義され、仮想関数を含むクラスが原因である可能性があります。すべての仮想関数がインラインで定義されている場合、コンパイラはヘッダーを含むすべての変換単位で仮想テーブルを生成し、リンカーがそれらを破棄できるように弱いシンボルとしてマークしますが、後で新しい仮想メソッドを追加し、ヘッダーで未定義のままにするか、仮想関数の1つから定義を削除すると、コンパイラは各変換単位では仮想テーブルを生成せず、それらの関数を定義するものでのみ生成します。

確認事項:

  • すべてのオブジェクトファイルをリンクしています
  • すべての仮想関数がクラス定義でインラインで定義されているか、仮想関数を定義する .cpp があり、それをリンクしています。
于 2011-01-04T12:25:41.093 に答える
1

これはデビッド・ロドリゲスが言ったことですが、もっと簡単に言っただけだと思います...

インターフェイスクラスでこの状況が発生しました:

class IBase
{
    public:
    virtual void begin(unsigned long);
    virtual void end();
    virtual int available(void) = 0;
    virtual int peek(void) = 0;
    virtual int read(void) = 0;
    virtual void flush(void) = 0;
}

これを次のように変更しました。

class IBase
{
    public:
    virtual void begin(unsigned long) = 0;
    virtual void end() = 0;
    virtual int available(void) = 0;
    virtual int peek(void) = 0;
    virtual int read(void) = 0;
    virtual void flush(void) = 0;
}

トリックを行いました。

begin() と end() は別のファイルの派生クラスで定義され、IBase クラス (インターフェイス) はヘッダーでのみ宣言され、いくつかの場所に含まれていました。

OPからのエラーは、最適化をなし(-O0)に設定した場合にのみ表示され、他の設定ではエラーは発生しませんでした(gcc 4.8)。

于 2015-03-31T03:16:31.457 に答える