2016-08-27 19 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); 
} 
} 

Когда я назвал Derived :: getLocation() из другого места, нет никакой ошибки , Но когда я назвал Derived :: getWidth(), он дал мне ошибку сегментации. Мне нужно скопировать тот же код из базового класса (например, скопируйте код getWidth в производный класс), чтобы избежать ошибки. Я также попытался использовать «using Base :: getWidth;», но все же дал мне ошибку сегментации. Кажется, что если метод базового класса содержит указатели t

+0

«... нет ошибки» - это вы знаете. Определите в этом какое-то здравомыслие. Должны ли быть ** два экземпляра 'Sprite', управляемых здесь? Один из них указывает на «Base :: sprite», а другой - на «Derived :: sprite»? Если нет, то у вас есть слишком много «спрайтов». И * пожалуйста *, включите в свой вопрос [минимальный, полный, проверяемый пример] (https://stackoverflow.com/help/mcve). – WhozCraig

+0

Почему у них обоих есть другой Sprite * с тем же именем? –

+0

Существует только один класс Sprite. Однако в производном классе после инициализации частного члена sprite мне нужно установить некоторое дополнительное свойство, используя метод sprite. Таким образом, конструктор отличается от базового класса. Таким образом, я должен объявить его в производном классе. – ohmygoddess

ответ

0

Итак, прежде всего - что такое сегментационная ошибка? Это нечто похожее на NullPointerException на Java или NullReferenceException на C#. Это происходит, когда вы пытаетесь получить доступ к нераспределенной памяти.

Почему это происходит? Вы забыли выделить память для указателя sprite, поэтому он указывает на некоторые не уточненные фрагменты памяти. Вы должны инициализировать его в конструкторе, используя new оператор вроде этого:

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

Если вы хотите жить опасно Вы также можете сделать следующее:

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

Но это не безопасно, потому что спрайт могут быть выделены в стеке, поэтому код, как это может сорвать хаос в вашей программе вызывает неопределенное поведение:

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

это опасное, потому что после выхода из getBase функция нет sprite больше в памяти.

Update:

Поэтому в основном то, что я пришел к выводу от вас комментарии, что вы не вызываете надлежащего конструктор вашего Base класса. Ваш Derived конструктор должен выглядеть следующим образом:

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

Если вы не сделаете это, вы не установите значение sprite для базового класса. Ваше поле sprite вашего производного класса просто затеняет поле sprite вашего Base класса. Это как:

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

В примере глобальной i не изменилась, потому что она была слежка.

Ваш код работает после того, как дублируя метод getWidth() в Derived классе, потому что он был доступ затем sprite поле вашего Derived класса. Чтобы быть ясным - без переопределения метод getWidth() обращается к полю sprite класса Base, когда вы его переопределяете, он обращается к полю класса Derived.

+0

Я использовал новое ключевое слово для инициализации указателя, см. Обновленный код. все работает отлично, если я дублирую его код базового класса в производном классе. – ohmygoddess

+0

Какую часть кода вы дублировали? –

+0

Метод getWidth. Если я скопирую его в производном классе, все будет хорошо. Но я думал, что мне не нужно это делать, потому что присуще – ohmygoddess

0

Возможно, вы забыли указать переменную-член sprite внутри вашего конструктора. Сделайте что-то вроде этого: Base(Sprite * s): sprite(s) {} или Base(Sprite * s) { this->sprite = s; }.

Derived(Sprite* sprite) конструктор должен передать sprite к родительскому конструктору, как это: Derived(Sprite* sprite): Base(sprite) {};

Обратите внимание, что при существующем положении вещей в Base конструктор должен быть принят действительным Sprite* из Derived конструктора для getLocation() работать над экземплярами Derived ,

+1

Вам нужно решить другие проблемы с помощью Sprite *, если вы отправляете ответ. По крайней мере, отметьте правило из трех, пожалуйста. :) –

+0

Я инициализировал спрайт в базовом классе, это общий движущийся объект. В производном классе, который является классом игрока, я также определил класс спрайтов, но не через конструктор базового класса, я просто вызываю конструктор спрайтов, как в базовом классе. Это имеет значение? – ohmygoddess

+0

@ohmygoddess, да, потому что, когда вы вызываете 'getLocation()', он будет видеть только спрайт 'Sprite *' класса 'Base'. Так что делать то, что вы делали, означает, что он просто никогда не увидит и поэтому никогда не будет использовать тот, который вы создали для своего экземпляра 'Derived'. – user268396

Смежные вопросы