2010-07-12 10 views
5

ich zwei Klassen haben, Punkt und Pixel:C++ Vererbung/template Frage

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; 
} 

hier ist jetzt mein Problem. Ich möchte eine Container-Klasse erstellen (nennen wir es coll), die einen privaten Vektor von Punkten oder Pixeln hat. Wenn eine Instanz von coll Pixel enthält, möchte ich, dass sie eine Methode toArray() hat, die ihren Vektor von Pixeln in ein Array von T umwandelt, das den Inhalt des Vektors darstellt.

Ich würde dies mit Vererbung tun: dh, ich könnte eine Basisklasse coll machen, die einen Vektor von Punkten und eine abgeleitete Klasse enthält, die die Extra-Methode enthält, aber dann scheint ich auf Probleme zu stoßen, da Pixel ein ist Klassenvorlage.

Hat jemand Vorschläge? Könnte ich das irgendwie tun, indem ich coll eine Klassenvorlage mache?

+0

Ich denke, dass 'coll' auch eine Vorlagenklasse sein sollte. Dann können Sie 'coll' für Punkte und für Pixel teilweise spezialisieren. – Philipp

+0

Ist ein Pixel eine Menge von Koordinaten (d. H. Erbt "Punkt") oder hat er Koordinaten (d. H. Enthält eine Instanz eines Punkts)? – Patrick

+0

Erbt von Punkt. – amc

Antwort

3

Frage: Meinen Sie, dass der private Vektor sowohl Punkte als auch Pixel gleichzeitig oder nur eins oder zwei enthält?

Frage: Wenn Sie nur eines oder das andere wollen, wollen Sie Pixel mit verschiedenen Vorlagenparametern im selben privaten Vektor mischen?

Unter der Annahme, dass es nur Punkt oder Pixel im privaten Vektor ist, und dass die Pixel im privaten Vektor alle die gleichen Template-Parameter haben, könnten Sie so etwas tun:

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

Antwort: nur das eine oder das andere. Antwort: nur Pixel mit dem gleichen Template-Parameter. Diese Lösung scheint ziemlich gut zu sein, aber meine Sammlungen werden viele der gleichen Funktionalität haben: Wird dies nicht viel Doppelarbeit des gleichen Codes erfordern, da CollectionBase keinen Zugriff auf die Container haben wird? – amc

+0

@amc aktualisierte Antwort, um Code-Duplizierung zu verhindern. Es macht die PointCollection irgendwie überflüssig, aber das verhindert die meisten Umwandlungen von PixelCollection zu PointCollection und umgekehrt. Wenn Sie beabsichtigen, dass sie ineinander umgewandelt werden, können Sie CollectionBase und PointCollection einfach in einer einzigen Klasse zusammenfassen. – diverscuba23

+0

FANTASTISCH, das ist genau das, was ich wollte. Ich denke, ich habe nicht erkannt, dass Sie eine Vorlagenklasse ableiten können. Vielen Dank! – amc

1

Wenn Sie möchten, Überprüfen Sie, ob ein point Objekt auch eine Art von pixel<T> ist, dann können Sie einfach sehen, ob dynamic_castNULL zurückgibt. Um dies zu tun, muss point polymorph sein, also fügen Sie einen virtuellen Destruktor hinzu.

Hier ein Beispiel:

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>."; 
} 

Der Ausgang ist wie folgt:

y ein Pixel < int>.

Sie können diesen Code in Ihre coll-Klasse verwenden, um zu überprüfen, ob jedes Element eines vector<point *> ein Punkt oder ein Pixel. Aber um dies zu tun, würden Sie wissen müssen, um die Spezialisierung des Pixels gespeichert wird (das heißt, es ist ein pixel<int> oder ein pixel<float>?)

Es kann einfacher sein coll eine Klassenvorlage stattdessen zu machen.

1

Wenn collection behandelt point s und pixel s meist gleich und nur das eine oder das andere enthält, ist es sinnvoll, es zu einer Vorlagenklasse zu machen.
In Bezug auf to_array jedoch könnte es einfacher sein, es eine freie Funktion zu machen, statt:

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

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

Beachten Sie, dass eine öffentliche Schnittstelle zu schaffen, für den Lesezugriff auf die Daten jedoch oder zumindest to_array() Zugang selektiv gewähren habe .