2010-07-12 21 views
5

Ho due classi, punti e pixel:C++ eredità/template domanda

class point { 
    public: 
     point(int x, int y) : x(x), y(y) { }; 
    private: 
     int x, y; 
} 

template <class T> 
class pixel : public point { 
    public: 
     pixel(int x, int y, T val) : point(x, y), val(val) { }; 
    private: 
     T val; 
} 

Ora qui è il mio problema. Voglio creare una classe contenitore (chiamiamola coll) che ha un vettore privato di punti o pixel. Se un'istanza di coll contiene pixel, voglio che abbia un metodo toArray(), che converte il suo vettore di pixel in una matrice di T che rappresenta il contenuto del vettore.

Stavo per farlo con l'ereditarietà: cioè, potrei creare un coll di classe base che contenga un vettore di punti e una classe derivata che contiene il metodo extra, ma poi mi sembra di imbattersi in problemi poiché pixel è un modello di classe.

Qualcuno ha suggerimenti? Potrei farlo in qualche modo creando un modello di classe coll?

+0

Penso che 'coll' dovrebbe essere anche una classe template. Quindi puoi parzialmente specializzare 'coll' per punti e per pixel. – Philipp

+0

Il pixel è un insieme di coordinate (ad esempio "punto" ereditario) o ha delle coordinate (ad esempio, contiene un'istanza di punto)? – Patrick

+0

Si eredita dal punto. – amc

risposta

3

Domanda: Intendi per il vettore privato contenere contemporaneamente punti e pixel o solo uno o l'altro?

Domanda: Se solo uno o l'altro, intendi mischiare Pixel con parametri di modello diversi nello stesso vettore privato?

Supponendo che si tratta solo punto o pixel nel vettore privato, e che i pixel nel vettore privato hanno tutti lo stesso parametro di template, si potrebbe fare qualcosa di simile:

template < class T > class CollectionBase 
{ 
    //common interface here 
    protected: 
    std::vector<T> coll_vec; 
}; 

class PointCollection : public CollectionBase<Point> 
{ 
    public: 
    ... 
}; 

template< class T> PixelCollection : public CollectionBase<Pixel<T> > 
{ 
    public: 
    Pixel<T>* toArray(); 

    ... 

}; 
+0

Risposta: solo uno o l'altro. Risposta: solo pixel con lo stesso parametro del modello. Questa soluzione sembra abbastanza buona, ma le mie raccolte avranno molte delle stesse funzionalità: non richiederà molto la duplicazione dello stesso codice dal momento che CollectionBase non avrà accesso ai contenitori? – amc

+0

@amc ha aggiornato la risposta per impedire la duplicazione del codice. In qualche modo rende PointCollection un po 'ridondante, ma ciò impedirà la maggior parte dei cast da PixelCollection a PointCollection e viceversa. Se si intende consentire il cast tra loro, è possibile comprimere CollectionBase e PointCollection in un'unica classe. – diverscuba23

+0

INCREDIBILE, questo è esattamente quello che volevo. Immagino di non rendermi conto che potresti creare una sottoclasse di una classe template. Grazie! – amc

1

Se si desidera controlla se un oggetto point è anche un tipo di pixel<T>, quindi puoi semplicemente vedere se dynamic_cast restituisce NULL. Per fare questo, point dovrà essere polimorfo, quindi aggiungere un distruttore virtuale ad esso.

Ecco un esempio:

point x(0, 0); 
pixel<int> y(0, 0, 0); 
point *pX = &x; 
point *pY = &y; 
if(dynamic_cast<pixel<int> *> (pX) != NULL) { 
    std::cout << "x is a pixel<int>."; 
} 
if(dynamic_cast<pixel<int> *> (pY) != NULL) { 
    std::cout << "y is a pixel<int>."; 
} 

L'uscita è il seguente:

y è un int pixel <>.

Si potrebbe utilizzare questo codice nella classe coll per verificare se ogni elemento di un vector<point *> è un punto o un pixel. Ma per fare ciò, si avrebbe bisogno di sapere che la specializzazione di pixel viene memorizzato (vale a dire è un pixel<int> o un pixel<float>?)

Potrebbe essere più semplice per fare coll un modello di classe, invece.

1

Se collection tratta point s e pixel s principalmente lo stesso e contiene solo l'uno o l'altro, ha senso renderlo un modello di classe.
Per quanto riguarda to_array tuttavia, potrebbe essere più semplice per renderlo una funzione libera invece:

template<class T> struct collection { 
    std::vector<point<T> > data_; 
    // ... 
}; 

template<class T> 
void to_array(const collection<point<T> >& in, point<T>* out) { 
    // ... 
} 

Nota che si avrebbe per fornire un'interfaccia pubblica per l'accesso in lettura ai dati però, o almeno in modo selettivo concedere to_array() accesso .