Ошибка сегмента C ++ при обращении к сохраненному указателю базового класса - PullRequest
2 голосов
/ 02 февраля 2010

Я получаю некоторые неприятные ошибки сегментации через компилятор g ++ в следующем коде. Любые идеи о том, почему это произойдет и как это исправить, будут великолепны.

#include <iostream>
using namespace std;

class Base {
public:
  Base() {}
  virtual ~Base() {};
  virtual int getNum(int) = 0;
};

class Derived: public Base {
public:
  Derived() :
    Base() {}
  ~Derived() {}

  int getNum(int num) {
    return num;
  }
};

class Foo {
public:
  Foo() {
  };
  void init() {
    Derived n;
    *baseId = n;
  }
  void otherStuff() {
    cout << "The num is" << baseId->getNum(14) << baseId->getNum(15) << baseId->getNum(16) << baseId->getNum(15) << endl;
  }
  Derived* baseId;
};

int main() {
  Foo f;
  f.init();
  f.otherStuff();
  return 0;
}

Ответы [ 3 ]

7 голосов
/ 02 февраля 2010

Здесь:

void init() {
    Derived n;
    *baseId = n;
}

указатель baseId никогда не инициализируется, что приводит к неопределенному поведению при его разыменовании.Это может быть хорошая идея, чтобы объяснить, что вы пытаетесь сделать здесь.Если вы хотите сохранить указатель на Derived или Base, но который начинается с указания на производное, вы можете сказать:

void init() {
    baseId = new Derived;
}

, но тогда вам, вероятно, понадобится конструктор копирования, оператор присваивания идеструктор для управления указателем.

Кроме того, по нескольким причинам написание функции init () обычно не является хорошей идеей - вам лучше выполнять работу непосредственно в конструкторе или его списке инициализации.

3 голосов
/ 02 февраля 2010

Когда вы звоните f.init(), baseId член Foo не инициализируется, но вы разыменовываете его в init(). Вы уверены, что не хотите чего-то большего по линии:

baseId = new Derived()
2 голосов
/ 02 февраля 2010
  void init() {
    Derived n;
    *baseId = n;
  }

Помимо того, что заметил Нил, производная n является локальной для вашей функции инициализации.Он «умирает», когда вы выходите из функции, поэтому, даже если вы его правильно присвоили, он не будет работать.

То, что вы хотите, это не назначение в стеке, а в куче:

  void init() {
    baseId = new Derived();
  }

или даже лучше:

  void init() {
    delete baseId;
    baseId = new Derived();
  }

и пара деструктор и конструктор, чтобы предотвратитьпроблемы:

Foo() : baseId(0) {};
~Foo() { delete baseId; }

При использовании этого метода обязательно либо block скопируйте конструктор и оператор присваивания, либо реализуйте их правильно.Однако для их реализации вам нужно будет также выполнить копирование Derived - или лучше: используйте безопасный shared_ptr для хранения указателя.

...