2009-04-02 56 views
1

私はまだC++を学んでいます。私は多態性がどのように機能するかを試していました。仮想メソッドを呼び出すときにセグメント化エラーが発生しました。このコードで仮想メソッドを呼び出すと、セグメンテーションフォルトが発生するのはなぜですか?

(注:私は、私は何が起こるか見にしようとしていた仮想としてデストラクタをマークしていなかった)ここでは、コードです:

#include <iostream> 

using namespace std; 

class Base 
{ 
protected: 
    char *name; 

public: 
    Base(char *name) 
    { 
    cout << name << ": Base class cons" << endl; 
    } 

    ~Base() 
    { 
    cout << name << ": Base class des" << endl; 
    } 

    virtual void disp(); 
}; 

void Base::disp() 
{ 
    cout << name << ": Base disp()" << endl; 
} 

class Child : public Base 
{ 
public: 
    Child(char *name): 
    Base(name) 
    { 
    cout << name << ": Child class cons" << endl; 
    } 

    ~Child() 
    { 
    cout << name << ": Child class des" << endl; 
    } 

    virtual void disp() 
    { 
    cout << name << ": Child disp()" << endl; 
    } 
}; 


int main() 
{ 
    //Base b; 
    //b.disp(); 
    Base c = Child("2"); 
    c.disp(); 
} 

は、また、あなたはに関するその他のヒントをしている場合Javaでこれらの概念を知っている人にとっては、一般的に継承と多型の使用方法について教えてください。ありがとうございました!

+0

エラーが発生し、呼び出し元のコードを表示してください:ここでは

は、両方のこれらの問題を修正したコードです。 – dwc

+0

baydaがそれを呼び出しました。セグメンテーションフォールトを修正するには、Baseコンストラクタを 'Base(char * name):name(name){...} 'のように書き直す必要があります。 –

答えて

8

名は - ベース

にいないに関わらずされても、あなたは別の問題を抱えている:

Base c = Child("2"); 

私はそれはあなたが望むものだとは思いません。あなたのコードは、キャストされた子からベースのインスタンスを作成します。しかし、私はBaseインターフェースに基づいてChildインスタンスを使って作業したいと思っています。あなたの代わりに書く必要があります。

Base *c = new Child("2"); 

をも、将来のバグを回避するために、仮想のような塩基でデストラクタを宣言します。

+0

したがって、多態的な振る舞いが必要な場合は、オブジェクトをヒープに格納する必要がありますか? – Srikanth

+1

実際にはありません。このようなことができます。子供a( "2");ベース* ptr =&a; – chappar

+1

いいえ。スタック上にオブジェクトを作成した後、Base ..の参照によってパラメータとして関数に渡すと、ポリモフィクの振る舞いになります。または@chapparの答え(前のコメント)のように。 – bayda

1

メンバーのchar * nameをあなたのctorsに割り当てているとは思われません。

1

おわかりです。

あり 、いくつかの問題ですが、あなたは char*を渡しているので、あなたのセグメンテーションフォルトはおそらくある - ちょうどポインタ、およびそれが disp()coutしようとしています。問題は、ポインタが disp()に存在しないことです。それは main()にあります。 char*をディープコピーするか、または std::stringを使用します。このようにすると動作しません。

EDIT

は、あなただけのクラスのname変数に名前を割り当てることはできませんEDIT 2

を参照してください。そうすると、予測できない結果が得られます。おそらく、セグメンテーションを止めるでしょう。覚えておいてください:C/C++では、オブジェクトはヒープに割り当てられていない限り、ローカルスコープです。

this->name = new char[ strlen(name) + 1 ]; 
strcpy(this->name, name); 

そしてデストラクタで、あなたのような何かをしたいと思う:

delete [] this->name; 

注:私の構文は5月この場合、あなたのctorでは、あなたのような何かをしたいと思います完全に間違っていると私はchar*をチェックしていないので、上記のコードが本質的に安全でないことに気付きます。戻り値がnew.ではないことを確認していません。

編集2: 私は訂正しました。文字列リテラルは、一定の記憶域として扱われ、したがってプログラムの期間中存続します。 でも、レッスンは重要です:一般的には、文字列リテラルを扱っていないときは、ポインタ(または配列など)を渡して、そのための記憶域を割り当ててディープコピーする必要があります。また、前記オブジェクトを破壊するときに適切に割り当てを解除する必要があります。

+0

これは問題ではありません。実際にパラメータを格納しています)。文字列リテラルは静的な記憶期間を持ちます。もちろん、誰かが動的または自動記憶期間を持つ文字列から子を作成し、その子がその文字列よりも長生きすることが問題になります。 –

+0

@FreeMemory - ここで言うことはすべて間違っています。文字列リテラルへのポインタを保持しても問題ありません。コピーする必要はありません。 –

+0

特に、標準の2.13.4/1と3.7.1/1を参照してください。 –

4

あなたは変数nenberベースを初期化することはありません - あなたのベースのコンストラクタは次のようになります。

Base(char * aname) : name(aname) 
    { 
    cout << name << ": Base class cons" << endl; 
    } 

としてだけでなく、その、あなたが

Base b = Child("xxx"); 

を言うとき、子インスタンスは、までスライスされますベース、これはおそらくあなたが望むものではありません。

1

Child :: disp()メソッドは決して呼び出されません.cは、ポインターや参照ではなく、Base型の変数で、仮想メソッドをチェックしません。

Base * c = new Child("1"); 
c->disp(); 
delete c; 

は、Child :: disp()を呼び出します。

0

ここにはいくつかの問題があります。まず、基本クラスのデストラクタは仮想でなければなりません。それ以外の場合、基本クラスのデストラクタは派生オブジェクトを指していても常に呼び出されます。次に、派生クラスオブジェクトを基底クラスオブジェクトに割り当てるべきではありません。これはオブジェクトスライシングと呼ばれます。 したがって、代入はポインタまたは参照によって行う必要があります。

セグメンテーションの問題は、ガベージ値が含まれているために発生しています。コンストラクタで初期化する必要があります。

0

コードにいくつか問題があります。名前:

まず、あなたはセグメンテーションフォルトを取得する理由は、ベースのctorの実装では、クラスの

class Base 
{ 
protected: 
    char *name; 

public: 
    Base(char ***name**) 
    { 
    cout << name << ": Base class cons" << endl; 
    } 

CTORのパラメータメンバ変数」の一つとして同じ名前のパラメータを取りれます'hides同じクラスのメンバ変数erm ... name。

第二に、あなたがここにslicingあなたのオブジェクトです:

int main() 
{ 
    //Base b; 
    //b.disp(); 
    Base c = Child("2"); 
    c.disp(); 
} 

「c」が型ベースのものであり、あなたはそれに子供を割り当てようとしています。 ogbjectを基本クラスに割り当てると、Childに固有のすべてのものがスライスされます。

#include <iostream> 
#include <string> 

using namespace std; 

class Base 
{ 
protected: 
    std::string name_; 

public: 
    Base(char *name) 
     : name_(name) { 
    cout << name_ << ": Base class cons" << endl; 
    } 

    ~Base() 
    { 
    cout << name_ << ": Base class des" << endl; 
    } 

    virtual void disp(); 
}; 

void Base::disp() 
{ 
    cout << name_ << ": Base disp()" << endl; 
} 

class Child : public Base 
{ 
public: 
    Child(char *name): 
    Base(name) 
    { 
    cout << name_ << ": Child class cons" << endl; 
    } 

    ~Child() 
    { 
    cout << name_ << ": Child class des" << endl; 
    } 

    virtual void disp() 
    { 
    cout << name_ << ": Child disp()" << endl; 
    } 
}; 


int main() 
{ 
    //Base b; 
    //b.disp(); 
    Base * c = new Child("2"); 
    c->disp(); 
    delete c; 
} 
関連する問題