Definitionen von Template-Klassen-Methoden in die Klassendeklaration oder unterhalb?
-
Hallo,
bei normalen Klassen sollte man die Methoden-Definitionen von längeren Methoden ja in die Implementationsdatei auslagern. Das soll man bei Template-Klassen ja nicht machen.
Sollte man dann die Definitionen direkt in die Klassendeklaration schreiben oder unterhalb der Klasse? Also#ifndef STAPEL_H #define STAPEL_H #include <valarray> #include <stdexcept> template <typename T> class Stapel : private valarray<T> { ... T const& pop () { if ( _hoehe == 0 ) throw out_of_range( "Stapel ist leer!" ) ; --_hoehe ; return (*this)[ _hoehe ] ; } ... } #endifoder
#ifndef STAPEL_H #define STAPEL_H #include <valarray> #include <stdexcept> template <typename T> class Stapel : private valarray<T> { ... T const& pop () ; ... } template<typename T> T const& Stapel<T>::pop() { if ( _hoehe == 0 ) throw out_of_range( "Stapel ist leer!" ) ; --_hoehe ; return (*this)[ _hoehe ] ; } #endif?
Danke,
Thilo
-
Thilo87 schrieb:
Sollte man dann die Definitionen direkt in die Klassendeklaration schreiben oder unterhalb der Klasse? Also
Das ist reine Geschmackssache. Ich nutze ersteres nur in einfachen Fällen, letzteres finde ich bei komplexeren Klassen oder Methoden, die mehr als Einzeiler sind, übersichtlicher.
-
Ist denke ich dir überlassen. Je nachdem wie es übersichtlicher ist.
Meine Meinung: Kurze, triviale Methoden (z.B. Setter, Getter) direkt in die Klassendeklaration, längere danach (dein Pop würde ich auch eher zu den längeren zählen). Sonst wird die Klassendeklaration zu unübersichtlich.
-
Sollte man dann die Definitionen direkt in die Klassendeklaration schreiben oder unterhalb der Klasse?
Ich empfehle dir alles in die Klassendefinition zu packen was du kannst. Außerhalb kommt nerviger Boilerplate dazu. Wenn die Funktionen zu lang werden als dass man sie in der Klasse behalten könnte ist das sowieso ein tendenziell schlechtes Indiz!
dein Pop würde ich auch eher zu den längeren zählen
Vier Zeilen ist nicht lang -
popsollte hier IMO in die Klassendefinition.
-
if ( _hoehe == 0 ) throw out_of_range( "Stapel ist leer!" ) ; --_hoehe ; return (*this)[ _hoehe ] ;->
assert(_hoehe > 0); return (*this)[ --_hoehe ];: private valarray<T>Äussert kontrovers, ich hätte valarray als Member genommen, das macht den Code übersichtlicher. Aber solange die Vererbung privat bleibt, ist das ok.
T const& Stapel<T>::pop()T const& zurückzugeben ist auch zweifelhaft. Bei deiner Implementierung rufst du den Destruktor nicht auf, das ist für den Anwender unerwartet. Mindestens dokumentieren, besser ändern.
Ich behalte Klassendefinitionen fast immer ausschliesslich im Header. Klassen machen das nötigste und stellen gekapselten Zugriff auf die Daten bereit, die komplizierten Algorithmen drauf führen freie Funktionen aus.
-
karl popper schrieb:
T const& Stapel<T>::pop()T const& zurückzugeben ist auch zweifelhaft. Bei deiner Implementierung rufst du den Destruktor nicht auf, das ist für den Anwender unerwartet. Mindestens dokumentieren, besser ändern.
Ja, da hatte ich auch überlegt. Problem ist eben, dass mit
T Stapel<T>::pop()bei der Rückgabe ja kopiert wird. Je nachdem, was der Stapel enthält, kann das eben schon an die Performance gehen.
Und
T& Stapel<T>::pop()wäre keine get-Methode mehr.
Würdet ihr trotzdem
T Stapel<T>::pop()verwenden?
Edit: Achso, sehe gerade, dass in der Aufgabe das const& vorgegeben war.
-
bei der Rückgabe ja kopiert wird.
Soll er ja auch. Sonst ist es recht doof dass man dangling references bekommen kann.
(Wenn überhaupt solltest du den Rückgabewert moven, nicht kopieren!)
-
Arcoth schrieb:
(Wenn überhaupt solltest du den Rückgabewert moven, nicht kopieren!)
Leider ist pop() nicht so einfach ausnahmensicher zu machen, wenn das gepoppte Element zurückgegeben wird.
-
Was meinst du mit moven? Als dynamisches Objekt zurückgeben?
-
Habe sowieso nie verstanden, warum die Funktionalität nicht getrennt (in T& top() und void pop()) wird, bei normalen Containern gibt es ja auch back() zum anschauen des letzten Elementes, und pop_back zum Entfernen desselben. Andererseits ist stack ja sowieso eine völlig überflüssiger Adapter.