code bewerten
-
jo, thx schon mal..
werd das morgen im zug korigieren..welchen vorteil haben denn const methoden?
das #include <iostream> sollte eigentlich eh nicht mehr drinn sein (war zum debugen)
sonst noch tipps?
-
@aman: das sie am Objekt/Exemplar selbst keine Aenderungen durchfuehren koennen, zb: falls du dich mal wo vertippen solltest und es unabsichtlich veraenderst bekommst einen Fehler beim kompilieren
-
warum haste in MyListElement denn MyList als friend deklariert, wo sowieso alle member öffentlich sind?
wenn MyList schon friend ist, sollten alle pointer schon private sein.
(is auch besserer stil.)das "this->" vor dem initialisieren kannst du dir eigentlich sparen, brauchst du nicht. ausser bei element, da muss der member dann natürlich anders heissen als das ctor-argument..
ganz gut find ich (das sehen andre wahrscheinlich wieder anders..) klassen-member immer mit unterstrich zu benennen, also zb: _element
dann reicht:template <class T> MyListElement<T>::MyListElement( T* element ) { _element = element; _next = 0; _prev = 0; }insgesamt gibts, glaub ich, schnuckligere wege solche listen zu implementieren, aber wenn du dir das alles selbst aus den fingern gesaugt hast, ist das schon ok!

-
Das die MyListElement pointer private sind, war auch vorgesehn.
ich hab das wohl auch beim debugen vergessen..wann ich this pointer verwenden muss, weiß ich selber. unser java lehrer hat gesagt, dass er this pointer immer verwendet
(wegen besserer uebersichtlichkeit -> bei this weiß er immer, dass sie vom obj. sind). ich hab das aber nicht konsequent durchgesetzt..
ist glaub ich auch das gleiche wie bei _vari oder m_vari..
this-> hat den vorteil, dass dann automatisch eine dropdownliste mit erreichbaren elementen kommt (im vc von micisoft kommt sie glaub ich immer -> find ich besser)
oder kann man das auch im kdev einrichten (und ich weiß nicht wo) ?da zeigt sich wieder, dass ich das ganze noch nicht im blut hab..
danke..morgen kommt die ueberarbeitete vers.
@prokaion
ich hab es anfangs teilweise hier abgeschaut (aber selber ausprogrammiert und eigentlich ist nicht mehr viel vom uhrspruenglichen uebrig):
http://www.mathematik.uni-marburg.de/~cpp/templates/index.html
[auf klassentemplates und dann paar mal weiter klicken]
-
.filmor schrieb:
NULL ist C, in C++ _sollte_ man 0 nehmen.
Das ist ja wohl geschmackssache. selbst wenn NULL als 0 definiert ist, kann man somit kennzeichnen, dass der zeiger ein nullzeiger ist. Natürlich ist das bei einer einfachen zuweisung nicht ausschalggebend, da versteht man beides, aber bei einer funktion setBuffer(NULL,0) weis man viel eher, was sache ist. Aber da bewegt man sich sehr im Bereich der persönlichen Code conventionen, und da macht eh jeder das, was er als das beste erachtet. Ich bin zumindest sehr gut damit gefahren, nullzeiger mit NULL zu bezeichnen, damit ich einen zeiger sehr schnell von anderen parametern(die zufälligerweise auch 0 sind) unterscheiden kann, wenn ich den Code überfliege.
-
- augenkrebs vermeiden (kommentare und das da => // #######################....)
- initialisierungsliste nutzen
- zeiger müssen im destruktor nicht auf 0 gesetzt werden, weil es sie dann sowieso nicht mehr gibt
- präfix-operator nehmen
- anstatt die kommentare in die funktion zu schreiben, lieber oben drüber, so wie bei doxygen. das ist ordentlicher und man kann doxygen verwenden
für NULL vs "0" => FAQ
setBuffer(NULL,0)sieht man sowieso nur bei c-wrappern, weshalb das meiner meinung nach kein argument ist.
-
terraner schrieb:
für NULL vs "0" => FAQ
setBuffer(NULL,0)sieht man sowieso nur bei c-wrappern, weshalb das meiner meinung nach kein argument ist.
std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.
-
otze schrieb:
Ich bin zumindest sehr gut damit gefahren, nullzeiger mit NULL zu bezeichnen, damit ich einen zeiger sehr schnell von anderen parametern(die zufälligerweise auch 0 sind) unterscheiden kann, wenn ich den Code überfliege.
Man darf sich dann nur nicht wundern, wenn bei einem NULL-Parameter die Überladung für int aufgerufen wird.
-
otze schrieb:
std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.
na da sind ja ganze ~6 methoden in der iostream-lib, die zeiger übernehmen. ein bisschen wenig im vergleich zum rest der stl. aber wenn du mir vielleicht noch die name einiger anderer libs nennen könntest, die null-pointer akzeptieren, überdenke ich nochmal meine meinung. ausgenommen sind natürlich funkionen wie z.b. std::time, da die ursprünglich aus c sind und man in c das mit überladung und standard-argumenten arbeiten könnte.
-
terraner schrieb:
otze schrieb:
std::cout.rdbuf()->pubsetbuf(NULL,0); schaltet buffering in der console aus.
na da sind ja ganze ~6 methoden in der iostream-lib, die zeiger übernehmen. ein bisschen wenig im vergleich zum rest der stl. aber wenn du mir vielleicht noch die name einiger anderer libs nennen könntest, die null-pointer akzeptieren, überdenke ich nochmal meine meinung. ausgenommen sind natürlich funkionen wie z.b. std::time, da die ursprünglich aus c sind und man in c das mit überladung und standard-argumenten arbeiten könnte.
Irrlicht
(z.b.: irr::createDevice(...,NULL); //NULL bezieht sich hier auf den EventReceiver)
-
terraner schrieb:
- augenkrebs vermeiden (kommentare und das da => // #######################....)
- initialisierungsliste nutzen
- zeiger müssen im destruktor nicht auf 0 gesetzt werden, weil es sie dann sowieso nicht mehr gibt
- präfix-operator nehmen
- anstatt die kommentare in die funktion zu schreiben, lieber oben drüber, so wie bei doxygen. das ist ordentlicher und man kann doxygen verwenden
@augenkrebs
ok, werd die kommentare ein bisschen umstellen..
@init. liste / zeiger im destruktor
hab ich geaendert
@praefix operator
was meinst du da genau?
@komentare wie bei doxygen
hm, meiner meinung sollten die komentare die funktionsweise erklaeren..
deshalb hab ich sie auch in die funktionen geschrieben.
werd sie aber noch ueberarbeiten..
@NULL vs 0
mir gefaellt eigentlich NULL besser. hat NULL geschwindigkeitsnachteile etc?
wird es wirklich so verachtet? (es ist ja kein prob alles auf 0 umzustellen..)mfg aMan
die neue vers. kommt auch gleich..
-
verbesserte version:
ich hab auch die deleteCurrentElement() methode umgebaut.
welche ist den beser (alte/neue)?@die ///####/// komentare
die trennen den haeder von der implementierung. ich habe jetzt nur noch eine zeile.
warum kann man eigentlich bei templates den code nicht von der implementierung trennen?mylistelement.h
#ifndef MYLISTELEMENT_H #define MYLISTELEMENT_H // #include "mylist.h" template <class T> class MyList; /** @author Adam Celarek */ template <class T> class MyListElement { private: MyListElement(T* element); ~MyListElement(); MyListElement* m_next; MyListElement* m_prev; T* m_element; friend class MyList<T>; }; ///########################################################################################/// ///#### con- / destructor template <class T> MyListElement<T>::MyListElement(T* element) : m_element(element) { m_next = NULL; m_prev = NULL; } template <class T> MyListElement<T>::~MyListElement() { delete m_element; } #endifmylist.h
#ifndef MYLIST_H #define MYLIST_H #include "mylistelement.h" /** @author Adam Celarek */ template <class T> class MyList { public: MyList(); ~MyList(); void append(T* element); // appends T* element and resets the next() function bool deleteCurrentElement(); // delete previously returned_element. so a current() after a // deleteCurrentElement() will always give a NULL // returns false if returned_element is NULL or if list_size is 0 unsigned int size() const; T* next(); // returns next_element; if the last element of the list // have been already returned, the function returns NULL T* current() const; T* first(); // returns first elem, and resets the next() function private: MyListElement<T>* m_first_element; MyListElement<T>* m_returned_element; // this element may be deleted / was returned by next (if not, then it's NULL) MyListElement<T>* m_next_element; // next element, that will be returned MyListElement<T>* m_last_element; unsigned int m_list_size; }; ///########################################################################################/// ///#### con/de-tructors #### template <class T> MyList<T>::MyList() { m_first_element=NULL; m_returned_element=NULL; m_next_element=m_first_element; m_list_size=0; } template <class T> MyList<T>::~MyList() { MyListElement<T>* current_element; current_element = m_first_element; while (current_element) // deletes the whole list; beginning at the first element { m_first_element = current_element->m_next; delete current_element; current_element=m_first_element; } } ///#### acces #### /*! \fn MyList::append() */ template <class T> void MyList<T>::append(T* element) { // 2 cases: // 1. there are no elements in the list // 2. there are elements in the list MyListElement<T>* new_element = new MyListElement<T>(element); if (m_list_size == 0) // case 1: no elements in the list { m_first_element=new_element; m_last_element=new_element; } else // case 2: the new element will be appended to the end of the list { m_last_element->m_next = new_element; new_element->m_prev = m_last_element; m_last_element = new_element; } first(); // resets the next() function m_list_size++; } /*! \fn MyList::deleteCurrentElement() */ template <class T> bool MyList<T>::deleteCurrentElement() { // no elements if (m_returned_element==NULL || m_list_size==0) { return false; } // changing pointers if (m_returned_element->m_next != NULL) m_returned_element->m_next->m_prev = m_returned_element->m_prev; if (m_returned_element->m_prev != NULL) m_returned_element->m_prev->m_next = m_returned_element->m_next; // if deleteting the first element if (m_returned_element == m_first_element) { m_first_element = m_next_element; } // if deleteting the last element if (m_returned_element == m_last_element) { m_last_element = m_returned_element->m_prev; } delete m_returned_element; m_list_size--; return true; } /*! \fn MyList::first() */ template <class T> T* MyList<T>::first() { m_returned_element = m_first_element; m_next_element = m_first_element->m_next; if (m_returned_element != NULL) return m_returned_element->m_element; else return NULL; } /*! \fn MyList::next() */ template <class T> T* MyList<T>::next() { if (m_next_element==NULL) { m_returned_element = NULL; // the m_next_element is only NULL, return NULL; // if the last position was already returned. } // it's even a check, so that the else clause can't make a segmentation fault else { m_returned_element = m_next_element; m_next_element = m_returned_element->m_next; return m_returned_element->m_element; } } /*! \fn MyList::current() */ template <class T> T* MyList<T>::current() const { if(m_returned_element!=NULL) return m_returned_element->m_element; else return NULL; } ///#### properties #### /*! \fn MyList::size() */ template <class T> unsigned int MyList<T>::size() const { return m_list_size; } #endif
-
aMan schrieb:
@praefix operator
was meinst du da genau?int i = 0; cout << "1: " << i << '\n'; cout << "2: " << ++i << ", " << i << '\n'; // präfix cout << "3: " << i++ << ", " << i << '\n'; // postfixhat NULL geschwindigkeitsnachteile etc?
wird es wirklich so verachtet? (es ist ja kein prob alles auf 0 umzustellen..)@topic speed: nein, weil es ein macro ist.
nein, imo ist es zum großen teil geschmackssache, ob man es einsetzt.
-
ok, danke..
@praefix operator
was das ist weiß ich schon, ich weiß nur nicht, wo ich ihn verwenden sollte..mfg aman..
-
aMan schrieb:
was das ist weiß ich schon, ich weiß nur nicht, wo ich ihn verwenden sollte..
Da, wo du m_list_size rauf- und runterzählst.
-
hmm..
warum ist da ein praefix oper. besser als ein post oper.?
-
aMan schrieb:
warum ist da ein praefix oper. besser als ein post oper.?
In dem Fall ist es egal, weil du den Rückgabewert nicht auswertest und es sich um einen eingebauten Datentyp handelt.
Aber es kann nicht schaden, wenn du dir angewöhnst, die Präfixversion zu benutzen, wenn es egal ist, damit du es automatisch richtig machst, wenn es nicht egal ist. Sieh einfach die Präfixversion als den Normalfall an und benutz die Postfixversion nur dort, wo du wirklich den "alten" Wert als Rückgabewert brauchst.
-
MFK schrieb:
otze schrieb:
Ich bin zumindest sehr gut damit gefahren, nullzeiger mit NULL zu bezeichnen, damit ich einen zeiger sehr schnell von anderen parametern(die zufälligerweise auch 0 sind) unterscheiden kann, wenn ich den Code überfliege.
Man darf sich dann nur nicht wundern, wenn bei einem NULL-Parameter die Überladung für int aufgerufen wird.
sicher. nur gut, dass es keinen sinnvollen Fall gibt, bei dem man als argument entweder einen int oder einen null-zeiger erwarten kann

-
otze schrieb:
nur gut, dass es keinen sinnvollen Fall gibt, bei dem man als argument entweder einen int oder einen null-zeiger erwarten kann

Nur gut, dass jeder Programmierer auf der Welt nur sinnvolle Überladungen erstellt

-
aMan schrieb:
warum kann man eigentlich bei templates den code nicht von der implementierung trennen?
Weil der Compiler bei der Verarbeitung des Templates wissen muß, (a) wie das Template aufgebaut ist (Quelltext) und (b) mit welchen Typen es verwendet wird (instantiierung). Die Informationen hat er nur zusammen, wenn du den Code direkt in dein Programm inkludierst.