2016-08-27 1 views
-3

を与える、私は次のような基底クラスと派生クラスがあるとします。C++派生クラスのコールベースクラスのメソッドは、セグメンテーションフォールトに

#include "Sprite.h" 
class Base{ 
    private: 
    int X; //location 
    Sprite* sprite; 
    public: 
    Base(Sprite* sprite){ 
     sprite = new Sprite(some parameter); 
    } 
    int getLocation(){ 
      return X; 
    } 
    int getWidth(){ 
     return sprite->getWidth(); 
    } 
} 


class Derived : public Base{ 
    private: 
     Sprite* sprite; // here I have to redefine it in constructor 
    public: 
     Derived(Sprite* sprite); // it's different that base constructor 
{ sprite = new Sprite(some parameter); 
    sprite->setPriperty(some parameter); 
} 
} 

私が派生呼び出されると::のgetLocation()他の場所から、エラーはありません。しかし、私はDerived :: getWidth()を呼び出すと、私にセグメント化エラーが発生しました。私は、フォールトを避けるために、ベースクラスから同じコードをコピーする必要があります(つまり、getWidthのコードを派生クラスにコピーする必要があります)。私も "Base :: getWidth;を使って"しようとしましたが、まだ、私にセグメンテーションフォールトを与えました。基本クラスメソッドにポインタが含まれていると思われる場合

+0

"...エラーはありません" - それはあなたが知っている。これでいくつかの正気を定義します。 ** ** Spriteインスタンスがここで管理されているはずですか? 1つは 'Base :: sprite'と' Derived :: sprite'で指摘されていますか?もしそうでなければ、あまりにも多くのスプライト*をホストしています。そして、*お願いします。あなたの質問には、[最小で完全で検証可能な例](https://stackoverflow.com/help/mcve)が含まれています。 – WhozCraig

+0

なぜ同じ名前のSprite *を持っているのですか? –

+0

Spriteクラスは1つだけです。しかし、派生クラスでは、プライベートスプライトメンバーを初期化した後、スプライトのメソッドを使用して追加のプロパティを設定する必要があります。したがって、コンストラクタは基本クラスとは異なります。したがって、派生クラスで宣言する必要があります。 – ohmygoddess

答えて

0

まず最初に、セグメンテーションフォールトとは何ですか? Javaの場合はNullPointerException、C#の場合はNullReferenceExceptionと類似しています。これは、割り当てられていないメモリーにアクセスしようとしたときに発生します。

どうしてですか? spriteポインタのためにメモリを割り当てるのを忘れてしまったので、それはあらかじめ用意されていないメモリチャンクを指しています。あなたは危険な住みたい場合は、以下のんでした

Base::Base(Sprite* sprite) { 
    this->sprite = new Sprite(sprite); 
} 

Base::Base(Sprite* sprite) { 
    this->sprite = sprite; 
} 

しかし、それは安全ではないですが、スプライトため、このようなnew演算子を使用して、コンストラクタでそれを初期化する必要がありますスタックに割り当てることができ、そのようなコードは未定義の動作を引き起こし、あなたのプログラムに大混乱を台無しことができます:

Base * getBase() { 
    Sprite sprite; 
    //some code operating on sprite 
    return new Base(&sprite); 
} 

それが原因で終了した後、危険なのですgetBase機能メモリにはもうspriteがありません。

更新:

だから、基本的に、私はあなたのコメントから結論何があなたのBaseクラスの適切なコンストラクタを呼び出すことはありませんということです。あなたのDerivedコンストラクタは次のようになります。これを行わない場合

Derived(Sprite* sprite): Base(sprite) { 
    ... 
} 

は、あなたの基本クラスのspriteの値を設定しないでください。派生クラスのspriteフィールドは、Baseクラスのspriteフィールドをシャドーイングしています。それは影にしたため、グローバルiが変更されていない例で

int i = 0; 
void fun() { 
    int i = 20; 
} 

:それはようなものです。

Derivedクラスのspriteフィールドにアクセスしていたので、コードはDerivedクラスのgetWidth()メソッドを複製した後に機能します。明確にするには、getWidth()メソッドをオーバーライドしないでBaseクラスのspriteフィールドにアクセスしています。オーバーライドすると、Derivedクラスのフィールドにアクセスします。

+0

私は新しいキーワードを使ってポインタを初期化しました。更新されたコードを見てください。派生クラスで基底クラスのコードを複製すると、すべて正常に動作します。 – ohmygoddess

+0

コードのどの部分を複製しましたか? –

+0

getWidthメソッド。派生クラスでコピーすると、すべて正常に動作します。しかし、私はそれを行う必要はないと考えた。 – ohmygoddess

0

おそらく、spriteメンバ変数をコンストラクタ内に設定することを忘れている可能性があります。次のようなことをしてください:Base(Sprite * s): sprite(s) {}またはBase(Sprite * s) { this->sprite = s; }物事はBaseコンストラクタをスタンドとしてDerivedのインスタンス上で動作するようにgetLocation()ためDerivedコンストラクタから有効なSprite*を渡さなければならないことをDerived(Sprite* sprite): Base(sprite) {};

注:

Derived(Sprite* sprite)コンストラクタは、このような親コンストラクタにspriteを渡す必要があります。

+1

回答を投稿する場合は、Sprite *のその他の問題に対処する必要があります。少なくとも3つのルールに言及してください。 :) –

+0

ベースクラスのスプライトを初期化しました。これは一般的な移動オブジェクトです。プレイヤークラスである派生クラスでは、スプライトクラスも定義しましたが、ベースクラスコンストラクターではなく、基本クラスのようにスプライトコンストラクターを呼び出します。それは重要ですか? – ohmygoddess

+0

@ohmygoddess、はい、 'getLocation()'を呼び出すと 'Base'クラスの' Sprite *スプライト 'しか表示されないので、したがって、あなたが行ったようなことをすることは、あなたが 'Derived'インスタンスのために作成したものを単に見ることはないので、決して使用しないことを意味します。 – user268396

関連する問題