2012-05-10 22 views
2

私はC構造体から派生したクラスを持っています。このクラスは、コンストラクタの初期化、デストラクタ中の初期化解除関数、およびC関数を呼び出すその他のいくつかのメソッド以外の特別なことはしません。基本的に、それは普通のラッパーです。 GCCを使って、私のデストラクタは仮想ではないと訴えたので、私はそれを作った。今私はsegfaultsに走ります。構造体から派生したクラスの仮想関数

/* 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関数でセグメンテーションを取得するので、これは当てはまりません。

キーワードvirtualを削除することで、コードは正常に動作しますが、gccの警告が表示されます。これに対して最善の対策は何ですか?私を啓発しても構いません:)

+1

A ::〜A virtualを作成できますか? –

+0

いいえ、できません。それはパブリックなCヘッダーです。 – MarkP

+0

構造体の代わりにクラスを使用してみませんか?違いは明らかですが、同じ目標が達成されています。 – Poni

答えて

4

明示的および暗黙的な共同A*への変換は安全です。明示的なキャストの必要はなく、どこでもvtableを導入する予定はありません。これが当てはまらないなら、言語は根本的に使えないだろう。

私はstatic_castを、仮想テーブルから ポインタを剪定、基底クラスへ 正しいポインタを返すという前提の下で常にでした。

は間違いありません。またはデストラクタが手動で起動 -

デストラクタはdelete ptr;ptrA*を入力した場合に呼び出された場合にのみvirtualあればよいです。そして、仮想でなければならないのはAのデストラクタでしょう。それはそうではありません。

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

+1

これはおそらく、不十分に提示され、研究された質問に照らして唯一の賢明な答えです。 –

1

基本クラスのデストラクタは仮想である必要があります。そうしないと、未定義の動作に陥る可能性があります。これは単なる推測であり、コードが実際の理由を伝えるには不十分です。

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

classstructは、デフォルトのアクセスレベル以外は同じものなので、クラスと構造体が何も関係しないという事実に注意してください。

EDIT:AがC構造体の場合は、継承の代わりにAメンバーを拡張する代わりに、Bのメンバーを使用します。多形性は問題にならないので、導き出す必要はありません。

+0

できません。公開されているCヘッダーに定義されています。 – MarkP

+0

@ MarkP ok、編集済みの回答を参照してください。 –

+1

Cの構造体を継承したくない理由を説明してください。私は、仮想キーワードが導入されると、仮想テーブルが追加されることを理解しています。それはまた構造体にvtableを追加しますか? (static_castを実行するときに、vtableでAを返しますか?) – MarkP

1

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

ポインタのキャストは実際にポインタ値を変更しない、つまり、同じタイプのメモリアドレスを指しているとします(A*ポインタ型にキャストされていても)。 structclassはC++の同義語です。

@Luchianによれば、CとC++を混在させているのであれば、普通の古いC構造体(とそのポインタ)を継承の代わりに普通の古いC構造体にしておく方が良いでしょう。さもなければ、カバーの下に異なるポインタ実装を混在させます。 C構造体とC++クラスの内部配列が同じであるという保証はありません。

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

または::

C++コンパイラは、構造体は、純粋なCの構造体であることを知っているように、あなたは、 extern "C"仕様とCの構造体宣言を囲む必要があります

UPDATE

extern "C" 
{ 
#include "c_header.h" 
} 
+0

それは、構造体自体のレイアウトを仮想的に変更するクラスを持つC構造体から継承していますか? – MarkP

+0

他に何もなければ、隠された 'vtable'メンバを追加します。 –

+0

@Loadmaster:いいえ、構造体にはvtableがありません。 'static_cast'はvtableのない' A'へのポインタを返します。 'static_cast'は問題ではありません。 –

関連する問題