2013-04-25 23 views
8

ho una classe template chiamato cellulare come segue: -C++: vettore di classe template

template<class T>class Cell 
{ 
    string header, T data; 
} 

Ora voglio un'altra classe denominata Row. La riga avrà un vettore chiamato Celle in modo tale da poter aggiungere elementi di tipo Cella e Cella a quel vettore. È possibile?

Se sì, come posso farlo? Grazie in anticipo.

+0

Vuoi una riga per contenere, ad esempio, una cella , una cella e qualsiasi altro tipo di cella in un vettore <>? – Skizz

+0

Sì hai ragione. Lo voglio esattamente. –

+0

significa che vuoi un contenitore polimorfico? è possibile utilizzare solo il polimorfismo dinamico (ereditarietà) e non il polimorfismo statico (modelli). – Elazar

risposta

12

Con dettaglio in più che ci hai fornito, le prime due risposte non funzioneranno. Quello che ti serve è un tipo noto come variante per la cella e quindi puoi avere un vettore di quelli. Ad esempio: -

enum CellType 
{ 
    Int, 
    Float, 
    // etc 
}; 

class Cell 
{ 
    CellType type; 
    union 
    { 
    int i; 
    float f; 
    // etc 
    }; 
}; 

class Vector 
{ 
    vector <Cell> cells; 
}; 

Questo, tuttavia, è un problema aggiungere nuovi tipi poiché richiede molto codice da mantenere. Un'alternativa potrebbe utilizzare il modello cella con una classe base comune: -

class ICell 
{ 
    // list of cell methods 
}; 

template <class T> 
class Cell : public ICell 
{ 
    T data; 
    // implementation of cell methods 
}; 

class Vector 
{ 
    vector <ICell *> cells; 
}; 

questo potrebbe funzionare meglio quando si dispone di meno codice inizialmente per aggiornare per aggiungere un nuovo tipo di cellula, ma è necessario utilizzare un tipo di puntatore nelle cellule vettore. Se hai memorizzato la cella in base al valore, vector <ICell>, perderai i dati a causa di object slicing.

+0

+1. unione non è solo dolore, non è anche sicuro dal tipo, che è l'intero scopo dei modelli. – Elazar

+0

Grazie mille. Userò il secondo metodo. Grazie a tutti i ragazzi che cercano di aiutarmi. –

+0

Un'altra cosa, puoi fornire codici di esempio per aggiungere elementi e accedere agli elementi usando iteratore? Grazie in anticipo. –

6

Qualcosa di simile?

template<class T> 
class Row 
{ 
private: 
    std::vector<Cell<T> > cells; 
}; 

OK, questa risposta non è corretta.

Quindi, se si desidera archiviare in una cella vector diverse, è necessario utilizzare un'identificazione di tipo dinamica (è possibile utilizzare un puntatore di classe base e archivio su di esso in vettoriale, che utilizza solo funzioni virtuali, sovrascritte in tutte le classi derivate, è possibile memorizzare qualcosa come boost::any e salvare alcuni type-identification per ogni elemento inserito, per convertirli in un tipo reale e lavorarci sopra).

+0

Jakir - nota lo spazio prima dell'ultimo '>', per evitare confusione con l'operatore '>>'. C++ 11 non ha bisogno di questo però. – Elazar

+0

Potrebbe non funzionare. Perché quando creo un oggetto di tipo Row devo fornire il parametro type. E il vettore sarà di quel tipo. –

+0

@JakirHossain Quindi è possibile aggiungere un altro parametro di modello. E usa quello per le cose specifiche di Row e usa T per le celle. – stardust

5

L'altra risposta è buona, ma probabilmente voleva:

template<class T> 
class Row 
{ 
private: 
    class Cell { 
     string header; 
     T data; 
    } 

    std::vector<Cell> cells; 
    ... 
} 
5

Il motivo per cui questo non è possibile in C++, ma possibile in Java/Python è perché: in C++ vettore, di stoccaggio del contenitore STL (restituito da vector :: dati()) contiene tutte le istanze di oggetti sequencially confezionato. In cui ogni elemento deve avere la stessa dimensione. Questo rende l'indirizzamento rapido e conveniente. Pertanto, si supponga di definire una classe modello A,

template <class T> 
class A{ 
    int id; 
    T obj; 
}; 

La sua dimensione dipenderà dalla variabile di modello "T obj". Spingere la stessa classe A di un diverso tipo di modello T renderà ogni elemento nel vettore di dimensioni diverse, quindi, questo è impossibile. L'unico modo è usare il vettore di shared_ptr o unique_ptr di una classe base. Sia shared_ptr che unique_ptr sono supportati da C++ 11 e Boost. Ogni elemento di classe derivata può avere diversi tipi di modello. In questo modo, quando viene chiamato il distruttore del puntatore della classe base, verrà richiamato il distruttore della classe derivata. Ad esempio,

#include <memory> 
#include <vector> 
#include <iostream> 
#include <string> 

using namespace std; 

class A{}; 

template <class T> 
class AImpl : public A{ 
public: 
    T obj; 
    AImpl(T _obj):obj(_obj){} 
    ~AImpl(){ 
     cout << "Deleting " << obj << endl; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    AImpl <string>* a1 = new AImpl <string> ("string1234"); 
    AImpl <int>* a2 = new AImpl <int> (1234); 
    AImpl <double>* a3 = new AImpl <double> (1.234); 
    vector <shared_ptr<A>> As; 
    As.push_back(shared_ptr<A>(a1)); 
    As.push_back(shared_ptr<A>(a2)); 
    As.push_back(shared_ptr<A>(a3)); 
} 

Ricordarsi di compilare con -std = C++ 11 per abilitare C++ 11.

uscita:

Deleting string1234 
Deleting 1234 
Deleting 1.234 

E si ottiene ciò che si vuole! :)

In Java/Python, ogni variabile oggetto di classe è in realtà un puntatore, quindi, una matrice Java di A o una lista Python di A è equivalente a una matrice C++ di puntatori di A. Quindi, si ottiene essenzialmente la stessa funzionalità senza creare esplicitamente shared_ptrs.

+0

Il tuo programma mostra l'errore come 'cpp: 25: 13: errore: 'shared_ptr' non è stato dichiarato in questo ambito' –

+0

@PraveenVinny Questo perché non hai compilato con -std = C++ 11. shared_ptr è in solo per C++ 11. – xuancong84

Problemi correlati