Llamar a un método de subclase provoca un error de segmentación [duplicado]
-
21-12-2019 - |
Pregunta
Estoy enfrentando un problema extraño.Escribí una clase abstracta principal (implementando un método test() virtual puro) y su clase secundaria (implementando el método test()).
class Parent
{
public :
Parent();
virtual ~Parent() = default;
virtual bool test() const = 0;
};
class Child : public Parent
{
public :
bool test() const;
};
Luego, escribí una clase "Grid" que se supone que contiene una matriz bidimensional de punteros a Parent.La matriz se realiza utilizando la biblioteca de vectores:"_cells" es un vector ancho*alto de punteros a Padre._cells se llena durante la construcción del objeto Grid mediante asignación dinámica y se libera en el destructor.Operador() (int a, int b) está sobrecargado para poder llamar al objeto principal usando este patrón:miGrid(x,y).
class Grid
{
int _w, _h;
std::vector<Parent*> _cells;
public :
Grid(int w = 0, int h = 0);
~Grid();
Parent* &operator()(int x, int y);
private :
void generate();
};
En mi función principal, g es una primera cuadrícula de 2x2 creada en la pila.Luego, se supone que debe destruir g y construir una nueva cuadrícula de 4x4 en g.Pero falla completamente:
Grid g(2, 2);
std::cout << g(1,1)->test() << std::endl; // Works perfectly
g = Grid(4, 4); // Probably wrong, but don't throw an exception
std::cout << g(1,1)->test() << std::endl; // SIGSEGV
Creo que el problema proviene de la asignación/desasignación dinámica de cada celda, pero no encontré una manera de resolverlo.
Aquí está mi código completo, no logré simplificarlo más.Hice mi mejor esfuerzo.Lo siento.
#include <iostream>
#include <cstdlib>
#include <vector>
class Parent
{
public :
Parent();
virtual ~Parent() = default;
virtual bool test() const = 0;
};
Parent::Parent()
{}
class Child : public Parent
{
public :
bool test() const;
};
bool Child::test() const
{
return true;
}
class Grid
{
int _w, _h;
std::vector<Parent*> _cells;
public :
Grid(int w = 0, int h = 0);
~Grid();
Parent* &operator()(int x, int y);
private :
void generate();
};
Grid::Grid(int w, int h) : _w(w), _h(h), _cells(w*h)
{
generate();
}
Grid::~Grid()
{
for (auto cell : _cells)
delete cell;
}
Parent* &Grid::operator()(int x, int y)
{
return _cells[x*_w+y];
}
void Grid::generate()
{
int cell_num;
for (cell_num = 0; cell_num < static_cast<int>(_cells.size()); cell_num++)
_cells[cell_num] = new Child();
}
int main()
{
Grid g(2, 2);
std::cout << g(1,1)->test() << std::endl;
g = Grid(4, 4);
std::cout << g(1,1)->test() << std::endl;
return 0;
}
Gracias.
Solución
El Grid
La clase no tiene un operador de asignación de copia, por lo que en su lugar se utilizará la versión generada por defecto del compilador.Es muy simple y sólo hace una copia superficial de los miembros.Eso significa que los punteros creados para el temporario objeto Grid(4, 4)
se copian (solo los punteros, y no lo que apuntan), y cuando el objeto temporal se destruye también lo son los punteros (en el destructor del objeto temporal).Esto te deja con un objeto. g
con punteros a la memoria ahora eliminada.
Te sugiero que leas sobre la regla de tres.