2010-07-09 10 views
6

Ho bisogno di memorizzare una serie di punti dati sotto forma di (nome, valore), in cui il valore potrebbe assumere diversi tipi.C++ Come creare un contenitore eterogeneo

Sto cercando di utilizzare un modello di classe per ogni punto di dati. Quindi, per ogni punto di dati che vedo, voglio creare un nuovo oggetto e reinserirlo in un vettore. Per ogni nuovo tipo, ho bisogno di creare una nuova classe dal modello prima. Ma non posso memorizzare gli oggetti creati in alcun vettore, poiché i vettori si aspettano lo stesso tipo per tutte le voci. I tipi che devo memorizzare non possono essere montati in una gerarchia di ereditarietà. Non sono correlati. Inoltre, in futuro potrebbero essere creati più tipi e non voglio modificare il servizio di archiviazione per ogni nuovo tipo. C'è un modo per creare un contenitore eterogeneo per memorizzare queste voci? Grazie!

+0

Mostra un modo per gestire il polimorfismo di runtime. Immagino sia correlato. https://youtu.be/vxv74Mjt9_0?t=16m8s –

+0

Possibile duplicato di [Come posso archiviare oggetti di tipi diversi in un contenitore C++?] (Https://stackoverflow.com/questions/4738405/how-can- i-store-objects-of-different-types-in-ac-container) –

risposta

7

La libreria boost ha probabilmente quello che stai cercando (boost :: any). Puoi rollare il tuo usando un approccio del puntatore avvolto se non puoi usare boost ...

+1

Grazie! Penso che "qualsiasi" funzionerà! Ho anche trovato un tutorial su questo basato su boost :: any. Eccolo, se qualcuno ha bisogno di questo! http://www.devx.com/cplus/10MinuteSolution/29757/1954 – Abhi

0

Stavo pensando che potresti avere solo una coppia (tipo, void *) e scrivere la tua funzione pop che getta il vuoto * a seconda sul tipo descrivi nella coppia e poi spinga questi in qualunque contenitore attiri la tua attenzione.

+0

come menzionato da Neil però, soggetto a errori e inefficiente, non lo consiglierei neanche a questo. Segui il suggerimento di Neil e usa l'ereditarietà o dai un'occhiata a boost :: any come sopra di 6502. – cjh

4

Il problema con contenitori di questo tipo è che quando si desidera accedere a qualcosa nel contenitore, è necessario determinarne il tipo e quindi eseguire il cast sul tipo effettivo in qualche modo. Questo è brutto, inefficiente e soggetto a errori, motivo per cui la scelta numero 1 in C++ è quella di usare l'ereditarietà, a meno che non si abbia una buona ragione per non farlo - qualcosa che non ho mai visto nella mia carriera C++.

+0

Grazie Neil! ... Quindi questi tipi di dati sono praticamente dappertutto, sono un insieme di manopole se ti piace . Possono essere long int, string, bool e così via :(Can not Use inheritance .. – Abhi

+1

Il problema con i vettori e le classi C++ è che non è possibile dichiarare un vettore di Base e quindi inserire le istanze di Derived all'interno. A causa di copia la filosofia di C++ qualsiasi implementazione di questo tipo per std :: vector (o qualsiasi altro std :: container) deve usare i puntatori (eventualmente quelli incapsulati) – 6502

+1

@Abhi In realtà puoi usare l'ereditarietà, ovvero come aumentare: qualsiasi operazione, cancella il tipo in una base privata che ha un tipo derivato dal modello che contiene i valori, questo è tutto nascosto all'interno di boost :: qualsiasi dove è l'operatore costruttore/assegnazione che cancella il tipo (sono modelli). Comunque suggerisco di riconsiderare il tuo design, –

9

boost::any è già stato consigliato, tuttavia è per qualsiasi cosa, quindi non ci si può aspettare molto da esso.

Se si conoscono i vari tipi in anticipo, è preferibile utilizzare boost::variant.

typedef boost::variant<Foo, Bar, Joe> variant_type; 

struct Print: boost::static_visitor<> 
{ 
    void operator()(Foo const& f) const { f.print(std::cout); } 

    template <class T> 
    void operator()(T const& t) const { std::cout << t << '\n'; } 
}; 

void func(variant_type const& v) // not template 
{ 
    boost::apply_visitor(Print(), v); // compile-time checking 
            // that all types are handled 
} 
Problemi correlati