Cómo asignar memoria para un objeto que no sé el tipo real de? C ++
-
29-09-2019 - |
Pregunta
Quiero guardar un objeto de alguna clase derivada como una propiedad de otro objeto.
El problema para mí es conocer el tamaño del objeto a ser almacenado, ya que puede ser cualquier clase derivada de una clase base dada. No puedo asignar memoria para el objeto de la clase base, a la derecha, ya que es más pequeño. Supongo, typeof operador que también acaba de dar el tamaño de la clase base, ¿verdad?
Aquí está mi código de ejemplo. Por favor, vea los comentarios de entender lo que quiero decir. Perdón por la falta de originalidad ...
BaseA {};
DerivedA1 : BaseA {public: void property() { cout << 1; }};
DerivedA2 : BaseA {public: void property() { cout << 2; }};
// etc. - several derived classes.
BaseB // Contains (or links to) an instance of class derived from BaseA.
{
public:
BaseA * instanceA;
BaseB (BaseA instanceAX)
{
// ??? => How to allocate memory for the object
// I don't know the real type of?
instanceA = new BaseA (instanceAX);
}
BaseB (BaseA instanceAX) { delete instanceA; }
};
main()
{
DerivedA1 instanceA1;
BaseB instanceB (instanceA1);
// Use "property" regardless of which derived class it belongs to.
instanceB.instanceA->property();
}
Me podría almacenar un puntero en lugar del objeto en sí, que sería más fácil. Pero no estoy seguro de querer depender de la persona que llama para retener la propiedad objeto de la vida de instancia instanceB .
Gracias!
Solución
Bueno, en primer lugar, ya que se pasa en su BaseA por valor, no por referencia o puntero, te conocen el tipo; es BaseA. BaseB fue copiado en un BaseA y que copia BaseA se envía a la función. Cualquier dato adicional en BaseB no está contenida en instanceAX. Esto se llama "rebanar".
Sin embargo, para responder a su pregunta, simplemente no lo hacen de esta manera. Se necesita una función clone () en su clase BaseB si se tiene la intención de trabajar de esta manera. Alternativamente, usted puede diseñar un puntero inteligente u otro objeto que pueda clonar la instancia para usted. Si busca mi nombre en comp.lang.c ++ junto con el clon () puede llegar a través de una discusión que tuve allí sobre esta última idea.
La función clon es, por supuesto, una función virtual que devuelve una copia del objeto actual:
struct BaseA
{
virtual BaseA* clone() const = 0;
};
struct BaseB : BaseA
{
BaseB* clone() const { return new BaseB(*this); }
};
Otros consejos
Veo dos posibilidades.
-
Dar
BaseA
una función miembro puramente virtual, tal vez llamadaclone
, que es responsable de generar una copia de la instancia que se llama sucesivamente. A continuación, el constructor deBaseB
podría convertirseBaseB (BaseA const &instanceAX) { instanceA = instanceAX.clone (); }
-
También puedes, simplemente evite pasar punteros primas y usar
boost::shared_ptr
lugar. De esta manera, ya que es de referencia contado, la persona que llama no puede causar una destrucción prematura de la derivaciónBaseA
que se utilizó para construirBaseB
. Habría que ajustarBaseA * instanceA;
leerboost::shared_ptr <BaseA> instanceA;
A continuación, el constructor deBaseB
podría ser:BaseB (boost::shared_ptr <BaseA> a) : instanceA (a) { }
El problema del primer abordaje es que algún programador cliente que hereda de, digamos DerivedA1
pueden olvidarse de poner en práctica clone
en su derivación. El problema principal de la segunda aproach sería exigir que cada usuario de BaseB
para asignar la propiedad objeto en el montón (Puesto que usted está haciendo una copia dentro BaseB
s constructor de todos modos, al menos, el consumo total de memoria no se elevaría, sin embargo)