Come allocare memoria per un oggetto che non conosco il tipo reale di? C ++
-
29-09-2019 - |
Domanda
Voglio memorizzare un oggetto di una classe derivata come una proprietà di un altro oggetto.
Il problema per me è conoscere la dimensione dell'oggetto da memorizzare, in quanto può essere qualsiasi classe derivata di una determinata classe di base. Non posso allocare memoria per oggetto la classe base, a destra, in quanto è più piccolo. Suppongo, typeof operatore sarebbe anche solo dare la dimensione della classe base, giusto?
Ecco il mio codice di esempio. Si prega, si vedano i commenti per capire cosa intendo. Mi scusi per l'unoriginality ...
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();
}
ho potuto memorizzare un puntatore invece che l'oggetto stesso, sarebbe stato più facile. Ma io non sono sicuro di voler fare affidamento sul chiamante per mantenere l'oggetto di proprietà per la vita di istanza instanceB .
Grazie!
Soluzione
Bene, prima di tutto, dal momento che si passa nella vostra BaseA per valore, e non con riferimento o un puntatore, vi conosco il tipo; è BaseA. BaseB è stato copiato in un BaseA e che copia BaseA viene inviata alla funzione. Tutti i dati in più in BaseB non è contenuta in instanceAX. Questo si chiama "affettare".
Ma, per rispondere alla tua domanda, è sufficiente non farlo in questo modo. Avete bisogno di una funzione di clone () nella classe BaseB se è destinato a lavorare in questo modo. In alternativa si potrebbe progettare un puntatore intelligente o un altro oggetto che può clonare l'istanza per voi. Se si cerca il mio nome su comp.lang.c ++ con clone () si potrebbe venire attraverso una discussione che ci fosse su quest'ultima idea.
La funzione di clone è, naturalmente, una funzione virtuale che restituisce una copia dell'oggetto corrente:
struct BaseA
{
virtual BaseA* clone() const = 0;
};
struct BaseB : BaseA
{
BaseB* clone() const { return new BaseB(*this); }
};
Altri suggerimenti
Vedo due possibilità.
-
Dare
BaseA
una funzione di membro puramente virtuale, forse chiamatoclone
, che è responsabile per generare una copia dell'istanza viene chiamato. Poi il costruttore diBaseB
potrebbe diventareBaseB (BaseA const &instanceAX) { instanceA = instanceAX.clone (); }
-
Si potrebbe anche solo evitare di passare i puntatori prime in tutto e l'uso
boost::shared_ptr
invece. In questo modo, dal momento che è di riferimento contati, il chiamante non può causare una distruzione prematura della derivazioneBaseA
che è stato usato per costruireBaseB
. Dovreste regolareBaseA * instanceA;
a leggereboost::shared_ptr <BaseA> instanceA;
Poi il costruttore diBaseB
potrebbe essere simile:BaseB (boost::shared_ptr <BaseA> a) : instanceA (a) { }
Il problema del primo aproach è che alcuni programmatore client che eredita da, diciamo DerivedA1
possono dimenticare di implementare clone
nella sua derivazione. Il problema principale del secondo aproach sarebbe richiedere ogni utente di BaseB
per allocare l'oggetto struttura sul mucchio (Poiché si effettua una copia all'interno BaseB
s costruttore comunque, almeno il consumo di memoria totale non salirebbe, però)