Klassenfrage :)
-
@Quiche-Lorraine
Natürlich ist die akademische Auseinandersetzung mit OOP oder sonstiger Informatik wichtig, aber ist es nich für jeden schwierig diese leicht verständlich darzulegen? (mach es besser wer kann) Und die größere Kritik verdient sich Jürgen Wolf durch seine Praxisfernen Beispiele. Für Informatiker mögen "foo" und "bar" zuordenbar sein doch "normale" Anwender haben damit Probleme. Ich weiß aus dem Stehgreif nicht ob Jürgen Wolf diese Begriffe verwendet, aber seine Beispiele sind Praxisfern im Handbucg zu c++11 und dem Grundkurs C aus dem Rheinwerkverlag. (Zeitarbeiter, Namen und Personalnummern sind nur für wenige Menschen von bedeutung)Ich habe keine Informatik-Literatur über die triviale hinaus gelesen um mir ein umfassendes weder Detailliertes Bild der OOP-Thematik verschaffen zu können, vielleicht ist die Kritik gerechtfertigt, doch die Praxisferne ist das größere Problem.
-
Natürlich will euch nicht die konkrete Lösung vorenthalten, auch wenn sie "erschreckend" einfach ist
class gui{ public: std::function<void(int)> button_funktion gui(std::function<void(int)> funktion){ button_funktion = funktion; } void onMouseOver(int x, int y, int taste){ if(x=bla) button_funktion(blub); } } void buttonKlick(int val){ if(val<1) tu das; else if(val<2)tuwas anderes; } void loop(){ while(1){ if(maus_x==gui_x) gui->onMouseOver(maus_x, maus_y, taste); else if(maus_x==on_exit) exit(0); } } gui *myGui; int main(){ myGui = new gui(buttonKlick); }
-
@EL-europ sagte in Klassenfrage :
Wie wäre es damit?
#include <functional> #include <iostream> class gui { public: std::function<void(int)> button_funktion; gui(std::function<void(int)> funktion) { button_funktion = funktion; } }; void buttonKlick(int val) { if (val < 1) std::cout << "tu das"; else if (val < 2) std::cout << "tuwas anderes"; } int main() { gui myGui(buttonKlick); gui myGui2([](int val) { if (val < 1) std::cout << "tu das"; else if (val < 2) std::cout << "tuwas anderes"; }); }
-
@Quiche-Lorraine
Ich will auch ausserhalb der main() durch andere Funktionen auf gui zugreifen können, deshalb hab ich sie als "*gui" "Zeiger" deklariert.
-
@EL-europ sagte in Klassenfrage :
Ich will auch ausserhalb der main() durch andere Funktionen auf gui zugreifen können, deshalb hab ich sie als "*gui" "Zeiger" deklariert.
Und ein Parameter kommt da nicht in Frage weil?
BTW:
Man sollte ggf. auch das Klassendesign anpassen.
-
BTW: Warum nutzt du überhaupt
new
und nicht z.B.std::unique_ptr
?
-
@Quiche-Lorraine
die Funktionalität einer GUI hab ich mit diesem Klassendesing vollends umsetzen können. Was fehlt ist ein nutzerfreundliches Verfahren bis zu 10 oder auch 100 tausend Farbwerte an die jeweiligen Parameter zu bekommen.
Da bin ich jetzt grad am spielen mit dem bisher errichtem um selbst "Erfahrung" zu sammeln.
-
@Quiche-Lorraine sagte in Klassenfrage :
BTW: Warum nutzt du überhaupt
new
und nicht z.B.std::unique_ptr
?was ist anderst daran, ausser das ich es nicht kenne?
-
@Quiche-Lorraine
bei Interesse: https://github.com/momefilo/mandelbrodt. Ist aber alles nackter Code ohne Kommentare
-
@EL-europ sagte in Klassenfrage :
was ist anderst daran, ausser das ich es nicht kenne?
Naja, das Schlüsselwort
new
allokierst du eine Ressource. Doch wer gibt diese wieder frei?Wenn du diese Frage nicht sauber beantworten kannst, bist du auf dem besten Weg ein Speicherloch in dein Programm zu reißen. Und dann crasht dein Programm im besten Fall. Im schlimmsten Fall dein Rechner, weil dein Program auf einmal mehrere Gigabyte RAM frisst.
Deswegen nutzt man die RAII Technik:
https://en.cppreference.com/w/cpp/language/raii
Kein
malloc
,new
,... sondern nurstd::unique_ptr
,std::vector
,...
-
@Quiche-Lorraine
Da triffst du den Nagel zumindest nah am Kopf:
Ich allociere in einer Klasse c-arrays, wenn ich Objekte dieser Klasse in std::vector speichere und diese Arrays im Destruktor mit free() freigebe, funktionieren entsprechende Methoden der Objekte in std::vector nicht mehr. Ich geb zu das die c-arrays und c-threads "quick n dirty" Lösungen sind weil ich meine thread-Lösung nicht einfach in c++ threads umgesetz bekam, wie den Rest des Codes
-
@EL-europ sagte in Klassenfrage :
bei Interesse: https://github.com/momefilo/mandelbrodt. Ist aber alles nackter Code ohne Kommentare
Sorry, wenn ich das mal sage. Aber dein Code is grausam:
- Du nutzt ungeniert
new
. Wer gibtmyApples.push_back(*new _AppleData);
wieder frei`? - Warum allokierst du eigentlich ständig Sachen, welche doch auch auf dem Stack liegen könnten?
- Wann darf ein Pointer bei dir NULL sein? Warum nutzt du kein
nullptr
? - Du missachtest komplett die Rule of Five! (https://en.cppreference.com/w/cpp/language/rule_of_three)
-> Du musst die Move Semantik beachten! (https://en.cppreference.com/w/cpp/language/move_constructor) - Warum nutzt du
malloc
und nichtstd::vector
? - Warum hast du einen Quicksort geschrieben und nutzt nicht
std::sort
? char iterText[17]; printf(iterText, "I-Werte % 8d", countsOfIter);
-> Das ist unter C++ ein völlig veralteter Programmierstil und eine potenzielle Buffer Overflow Sicherheitslücke. Nutzestd::format
!
Ein paar Cppcheck Sachen:
- Apple.cpp Line 127: Common realloc mistake: 'iterMembers' nulled but not freed upon failure
- Apple.cpp Line 65: '(void*)tmp_x' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined. Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1.
- Apple.cpp Line 182: Member variable '_Apple::xpos' is not initialized in the constructor. Member variables of native types, pointers, or references are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior.
- _Userinterface.cpp Line 152: Buffer is accessed out of bounds: text
- _Userinterface.cpp Line 8: When an object of a class is created, the constructors of all member variables are called consecutively in the order the variables are declared, even if you don't explicitly write them to the initialization list. You could avoid assigning 'callback' a value by passing the value to the constructor in the initialization list.
Das ist jetzt leider für dich ein wenig heftig und das tut mir auch Leid. Aber lerne daraus!
Vergiss das bisher gelernt und lerne aus einem richtig gutem C++ Buch.
- Du nutzt ungeniert
-
@Quiche-Lorraine sagte in Klassenfrage :
@EL-europ sagte in Klassenfrage :
bei Interesse: https://github.com/momefilo/mandelbrodt. Ist aber alles nackter Code ohne Kommentare
Sorry, wenn ich das mal sage. Aber dein Code is grausam:
- Du nutzt ungeniert
new
. Wer gibtmyApples.push_back(*new _AppleData);
wieder frei`? - Warum allokierst du eigentlich ständig Sachen, welche doch auch auf dem Stack liegen könnten?
- Wann darf ein Pointer bei dir NULL sein? Warum nutzt du kein
nullptr
? - Du missachtest komplett die Rule of Five! (https://en.cppreference.com/w/cpp/language/rule_of_three)
-> Du musst die Move Semantik beachten! (https://en.cppreference.com/w/cpp/language/move_constructor) - Warum nutzt du
malloc
und nichtstd::vector
? - Warum hast du einen Quicksort geschrieben und nutzt nicht
std::sort
? char iterText[17]; printf(iterText, "I-Werte % 8d", countsOfIter);
-> Das ist unter C++ ein völlig veralteter Programmierstil und eine potenzielle Buffer Overflow Sicherheitslücke. Nutzestd::format
!
Ein paar Cppcheck Sachen:
- Apple.cpp Line 127: Common realloc mistake: 'iterMembers' nulled but not freed upon failure
- Apple.cpp Line 65: '(void*)tmp_x' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined. Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1.
- Apple.cpp Line 182: Member variable '_Apple::xpos' is not initialized in the constructor. Member variables of native types, pointers, or references are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior.
- _Userinterface.cpp Line 152: Buffer is accessed out of bounds: text
- _Userinterface.cpp Line 8: When an object of a class is created, the constructors of all member variables are called consecutively in the order the variables are declared, even if you don't explicitly write them to the initialization list. You could avoid assigning 'callback' a value by passing the value to the constructor in the initialization list.
Das ist jetzt leider für dich ein wenig heftig und das tut mir auch Leid. Aber lerne daraus!
Vergiss das bisher gelernt und lerne aus einem richtig gutem C++ Buch.
Ich hab as prog von c in c++ umgeschrieben
zu Apple.line 127: Wenn ich den Arrays zuvor kein NULL zuweise zeigt es zur Laufzeit Speicherfehler.
Apple.line 65: Da meckert der Compieler weil er die Größe des Integerwertes nicht kennt, aber das Programm in der thFunc kennt sie
Apple.line 182: erst nach der Initialisierung durch init() ist die xpos berechnet, und wird zur laufzeit geändert.
userinterface 152: Da schneidet er die restlichen Stellen einfach ab, oder?
userinterface line8: Kann ich nicht nachvollziehen, es geschieht doch die Zuweisung im KonstruktorDoch danke für deine Hinweise, da hab ich noch ne compilermeldung:
include/_Colorinterface.cpp:245:86: warning: narrowing conversion of ‘(((_Colorinterface*)this)->_Colorinterface::elements.std::vector<_CiElement>::size() - 1)’ from ‘std::vector<_CiElement>::size_type’ {aka ‘long unsigned int’} to ‘int’ [-Wnarrowing]
Wenn ich versuche das letzte Objekt im std::vector mit der array.end() "-Funktion" anzusprechen, compiliert er mir nicht.
- Du nutzt ungeniert
-
@EL-europ sagte in Klassenfrage :
userinterface line8: Kann ich nicht nachvollziehen, es geschieht doch die Zuweisung im Konstruktor
Die Warnung spricht von der initialization list.
-
@Jockelx
Ich weiß nicht was genau die Initalisierungsliste bedeuted, aber diese Variable wird zur Laufzeit berechnet und wird public benötigt. Ich hoffe eure Compiler geben nur Hinweise aus das ich auf diese Variable ein Augenmerk haben soll, denn bei mir "meckert" er das nicht an
-
@EL-europ sagte in Klassenfrage :
Doch danke für deine Hinweise, da hab ich noch ne compilermeldung:
include/_Colorinterface.cpp:245:86: warning: narrowing conversion of ‘(((_Colorinterface*)this)->_Colorinterface::elements.std::vector<_CiElement>::size() - 1)’ from ‘std::vector<_CiElement>::size_type’ {aka ‘long unsigned int’} to ‘int’ [-Wnarrowing]List Inizialization (Initialisierung von
farbe2
in Zeile 245 in geschweiften Klammern) ist etwas penibler was die übergebenen Typen angeht. Diese Warnung bekommst du, weil du einenint
mit einem Ausdruckvector.size() - 1
initialisieren willst, der den Typvector<T>::size_type
hat, was meistens einuint64_t
ist (64 Bit ohne Vorzeichen statt 32 Bit mit Vorzeichen, wie es fürint
meistens der Fall ist).Um die Warnung wegzubekommen, kannst du z.B. den
id
-Member von_farbe
* zu einemstd::size_t
machen oder du castest den Ausdruck explizit in einenint
, wobei du sicherstellen solltest, dass dieser keine Werte außerhalb des Wertebereichs vonint
haben kann und dabei komische Sachen passieren können.Wenn ich versuche das letzte Objekt im std::vector mit der array.end() "-Funktion" anzusprechen, compiliert er mir nicht.
Die
end()
-Iteratoren von Containern verweisen nicht auf das letzte Element, sondern auf ein Element dahinter. Ein Zugriff auf dieses nicht-existierende Element ist Undefined Behaviour.Alternativen sind die Funktionen
vector.back()
odervector.at(vector.size() - 1)
/vector[vector.size() - 1]
, die eine Referenz auf das letzte Element zurückgeben (UB fallsvector
keine Elemente hat),vector.end() - 1
falls es sich um einen Bidirectional Iterator handelt (beivector
-Iteratoren der Fall) odervector.begin() + vector.size() - 1
(was aber nur bei einem Random Access Itetrator funktionieren sollte, das ist aber beivector
ebenfalls gegeben).* Namen die mit Unterstrich gefolgt von einem Kleinbuchstaben beginnen sind in C++ übrigens für die Implementation reserviert, also für den Compiler und die Standardbibliothek. Auch wenn das oft keine Probleme macht, ist es empfehlenswert, solche Namen zu vermeiden.
-
@Finnegan
Danke, die compiler-Meldung hab ich mit einem (int) cast wegbekommen und die Bereichsüberschreitung ist leicht in den Griff zu bekommen. Das mach ich jetzt... und der Hinweis mit den Unterstrichen, danke das wird Berücksichtigung finden
-
Ich hab zur Laufzeit manchmal Abbrüche mit der Meldung "malloc(): invalid size (unsorted)". Denke das kommt von den c-arrays?
Aber die thread Funktion bekomm ich in c++ ohne ein neues Buch nicht hin, und sie ist mein ganzer stolz (Und ich muss den ganzen Hirnschmalz noch mal investieren)ist es nicht schlimm schon Gedachtes nochmals denken zu müssen weil man Details vergessen hat? Das Alter!
-
@EL-europ sagte in Klassenfrage :
@Quiche-Lorraine
Da triffst du den Nagel zumindest nah am Kopf:
Ich allociere in einer Klasse c-arrays, wenn ich Objekte dieser Klasse in std::vector speichere und diese Arrays im Destruktor mit free() freigebe, funktionieren entsprechende Methoden der Objekte in std::vector nicht mehr. Ich geb zu das die c-arrays und c-threads "quick n dirty" Lösungen sind weil ich meine thread-Lösung nicht einfach in c++ threads umgesetz bekam, wie den Rest des CodesIch würde darauf wetten, dass die Klasse, die selbst Speicher alloziert kaputt ist und du die Rule of five nicht befolgst. Soll heißen, deine Klasse verhält sich anders, wenn Kopien von ihr angelegt werden, als du denkst.
Da ein Vektor mit wächst, kann es sein, dass die in ihm gespeicherten Objekte kopiert werden müssen.Solange du keine GUI Library verwendest (gerade für GUIs gibt es da schonmal ausnahmen) würde ich darauf wetten, das du hervorragend ohne
new
auskommst.- Nutze kein
new
und keinmalloc
- Du brauchst ein Array -> nutze
std::vector
- Du meinst Pointer zu brauchen -> nutze
std::unique_ptr
oderstd::shared_ptr
(bevorzugt ersteres)
Nutze keine globalen Variablen. Wenn du ein Objekt der Klasse wo anders brauchst, übergeb es als Parameter.
Wenn du die ersten drei Punkte befolgst, brauchst du wahrscheinlich keinen selbstgeschriebenen Destruktor mehr. Außerdem funktionieren Sachen, wie Objekte kopieren einfach so von sich aus richtig, oder lassen sich nicht kopieren (wenn ein
std::unique_ptr
als Member verwendet wurde)
.
- Nutze kein
-
@Schlangenmensch
Ich hab die Objekte der Klasse nicht mehr in std::vector, sonder "initialisiere" ein einziges Objekt mit anderen Parametern, und speichere die Parameter als struct in einem std::vector. Ich hoffte das die c-arrays damit laufen würden (ich vermute nur die c-arrays sind das prob)