2

C 構造体から派生したクラスがあります。このクラスは、コンストラクタでの初期化、デストラクタでの初期化解除関数、および C 関数を呼び出すその他のいくつかのメソッドを除いて、特別なことは何もしません。基本的に、これはありふれたラッパーです。GCC を使用すると、デストラクタが仮想ではないと不平を言われたので、そのようにしました。今、セグメンテーション違反に遭遇しました。

/* C header file */
struct A
{
  /* ... */
}

// My C++ code
class B : public A
{
public:
  B() { /* ... init ... */ }
  virtual ~B() { /* ... deinit ... */ }

  void do()
  {
    someCFunction(static_cast<A *>(this));
  }
};

static_cast私は常に、 が仮想テーブル ポインターを削除して、基本クラスへの正しいポインターを返すと想定していました。C関数でsegfaultが発生するため、これは当てはまらない可能性があります。

キーワードを削除するvirtualと、コードは正常に動作しますが、gcc 警告が表示されます。これに対する最善の回避策は何ですか? お気軽に教えてください:)。

4

3 に答える 3

4

への明示的および暗黙的な変換はどちらもA*安全です。明示的なキャストは必要ありませんし、vtables をどこかに導入することも、そのようなこともありません。そうしないと、この言語は根本的に使用できなくなります。

私は常に、static_cast が基本クラスへの正しいポインターを返し、仮想テーブル ポインターを削除すると想定していました。

絶対に正しいです。

デストラクタは、タイプがある場所で呼び出された場合、またはデストラクタが手動で呼び出されたvirtual場合にのみ必要です。そして、仮想でなければならないのは のデストラクタですが、そうではありません。delete ptr;ptrA*A

コードに問題が何であれ、表示されているコードとは何の関係もありません。サンプルを大幅に拡張する必要があります。

于 2012-05-10T19:36:43.787 に答える
1

それはどのようにstatic_cast機能するかではありません。オブジェクトへのポインタは、タイプが異なるだけで、引き続き同じポインタです。この場合、派生型(B)へのポインターを基本型()へのポインターに変換していますA

私の推測では、ポインタをキャストしても実際にはポインタ値は変更されません。つまり、A*ポインタタイプにキャストされていても、同じメモリアドレスを指していることになります。structclassはC++の同義語であることを忘れないでください。

@Luchianが述べたように、CとC ++を混在させる場合は、プレーンな古いC構造体(およびそれらのポインター)をプレーンな古いC構造体として保持し、継承の代わりに型合成を使用することをお勧めします。それ以外の場合は、内部でさまざまなポインター実装を混合しています。C構造体とC++クラスの内部配置が同じであるという保証はありません。

アップデート

extern "C"C ++コンパイラが構造体が純粋なC構造体であることを認識できるように、C構造体宣言を仕様で囲む必要があります。

extern "C"
{
    struct A
    {
        ...
    };
}

または:

extern "C"
{
#include "c_header.h"
}
于 2012-05-10T19:26:48.137 に答える
1

基本クラスのデストラクタは仮想でなければなりません。そうしないと、未定義の動作が発生する可能性があります。コードだけでは実際の理由を説明するのに十分ではないため、これは推測にすぎません。

A仮想のデストラクタを作成してみて、クラッシュするかどうかを確認してください。

classaと astructは、デフォルトのアクセス レベル以外は同じものであるため、一方がクラスで他方が構造体であるという事実は、それとは何の関係もないことに注意してください。

編集: AC 構造体の場合は、継承の代わりに構成を使用します。つまり、メンバーを拡張するのではなく、A内部に配置します。Bポリモーフィズムは問題外なので、導出する意味はありません。

于 2012-05-10T19:18:39.253 に答える