programacion - que es un objeto en c++
Almacenar objetos de clase derivados en variables de clase base (4)
Estás experimentando cortar. El vector copia el objeto derived
, se inserta uno nuevo de tipo Base
.
Me gustaría almacenar instancias de varias clases en un vector. Como todas las clases heredan de la misma clase base, esto debería ser posible.
Imagina este programa:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual void identify ()
{
cout << "BASE" << endl;
}
};
class Derived: public Base
{
public:
virtual void identify ()
{
cout << "DERIVED" << endl;
}
};
int main ()
{
Derived derived;
vector<Base> vect;
vect.push_back(derived);
vect[0].identify();
return 0;
}
Esperaba que imprimiera "DERIVADO", porque el método "identificar" es virtual. En cambio, ''vect [0]'' parece ser una instancia ''Base'' y se imprime
BASE
Creo que podría escribir mi propio contenedor (probablemente derivado del vector) de alguna manera que sea capaz de hacer esto (tal vez con sólo punteros ...). Solo quería preguntar si hay un método más C ++ ish para hacer esto. Y me gustaría ser completamente compatible con el vector (solo por conveniencia si otros usuarios alguna vez usan mi código).
Lo que estás viendo es Object Slicing .
Está almacenando el objeto de la clase Derivada en un vector que se supone que almacena objetos de la clase Base, esto lleva al corte de Objetos y los miembros específicos de la clase derivada del objeto que se está almacenando se cortan, así el objeto almacenado en el vector solo actúa como objeto de la clase base.
Solución:
Debes guardar el puntero al objeto de la clase Base en el vector:
vector<Base*>
Al almacenar un puntero a la clase Base, no habría cortes y también se podría lograr el comportamiento polimórfico deseado.
Como usted solicita una forma C++ish
de hacerlo, el enfoque correcto es usar un puntero inteligente adecuado en lugar de almacenar un puntero sin formato en el vector. Eso asegurará que no tenga que administrar manualmente la memoria, RAII lo hará automáticamente.
Usaría el vector<Base*>
para almacenarlos. Si dices vector<Base>
, se producirá un corte.
Esto significa que tendrá que eliminar los objetos usted mismo después de haber eliminado los punteros de su vector, pero de lo contrario debería estar bien.
TL; DR: No debe heredar de una clase públicamente copiable / movible.
De hecho, es posible evitar el corte de objetos en el momento de la compilación: el objeto base no debería poder copiarse en este contexto.
Caso 1: una base abstracta
Si la base es abstracta, no se puede crear una instancia y, por lo tanto, no se puede experimentar el corte.
Caso 2: una base de concreto
Si la base no es abstracta, entonces se puede copiar (por defecto). Tienes dos opciones:
- prevenir copia por completo
- permitir copia solo para niños
Nota: en C ++ 11, las operaciones de movimiento causan el mismo problema.
// C++ 03, prevent copy
class Base {
public:
private:
Base(Base const&);
void operator=(Base const&);
};
// C++ 03, allow copy only for children
class Base {
public:
protected:
Base(Base const& other) { ... }
Base& operator=(Base const& other) { ...; return *this; }
};
// C++ 11, prevent copy & move
class Base {
public:
Base(Base&&) = delete;
Base(Base const&) = delete;
Base& operator=(Base) = delete;
};
// C++ 11, allow copy & move only for children
class Base {
public:
protected:
Base(Base&&) = default;
Base(Base const&) = default;
Base& operator=(Base) = default;
};