C++ Objektorientierung ?

OP #7384141
Lesenswert?

Nachdem ich bei der Frage nach " 1<<PA3 " gründlich abgewatscht wurde, dabei aber auch reichlich gelernt habe, trau ich mich noch ein Problem anzusprechen.

Ich programmiere an einem Modellbauprojekt auf dem ArduinoMega256 in C++ unter Code::Blocks.

Es gibt eine main-Routine, an der ein paar ISR dranhängen, die z.b. Ereignisse zählen (Inkremente usw.)

In der main werden ein paar Klassen instanziert, z.b. die Klasse "segel", die Objekte sind dann "fock", "gross", "besan" usw.. Die Methoden darin heißen dann "bergen", "setzen" und sowas.

Ich würde gerne die genannten Objekte (z.b. fock) nicht in der main, sondern in einem anderen Objekt (z.b. "mannschaft" oder so) instanzieren, um die main übersichtlicher zu machen. (Anschaulich : die main ist der Skipper, die Mannschaft sind die Matrosen, und erst die machen die Arbeit..)

Mein Problem : Wenn ich ein Objekt nicht in der main, sondern in einem anderen Objekt erzeuge, kann das nicht auf die ISR-Werte aus der main zugreifen (oder andersrum).

Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben.

Was muß ich lernen, um das zu lösen ??

OP #7384160
Lesenswert?

Schwierig, ist viel Code... Hier die letzten Zeilen der main, und der Beginn der ersten ISR. Die ISR sind in der Datei main integriert, hängen unten dran (nicht im Programmkörper von main). In der mit "#####" gekennzeichneten Zeile wird ein Attribut der Klasse "segel", instanziert im Objekt "Gross", beschrieben. Das geht so nicht, wenn die Instanzierung von Gross nicht in der main, sondern einem anderen Objekt, geschieht.

Was tun ?

1
     }//ende der 10hz-task in der "while 1" -main-schleife
2
};//ende "while 1" - schleife innerhalb main
3
return 0;

}//ende von main ********************************************************

//Hardwarebelegung : //Timer 0 : PPM-Generator (für Servo und RC-Winden) //Timer 1 : 10HZ-Generator für NPRM-Scheduler //Timer 2 : PWM-Generator (A für Maschine ) //Timer 3 : Zähler für PPM-Decoder (vom RC-Sender) //Timer 4 : PPM für Winden in Gruppen //Timer 5 : Entprellung der Inkrementgeber //UART0 : USB zum PC //UART1 : GPS

ISR (PCINT0_vect) //Inkremente aus Gruppe 0 { if (int_done0 == 0) //falls das ein neuer interrupt ist { TCNT5 = 0; //Timer 5 auf Null int_done0 = 1; //merk dir, jetzt war ein signal } else { if (TCNT5 > 500) // letztes Signal länger als 32ms her ? { Gross.KlauInkrement ++ ; //############################ Besan.KlauInkrement ++ ; int_done0 = 0; } }

}

OP #7384178
Lesenswert?

Fällt mir echt schwer, das sauber zu beschreiben.

Normalerweise referenziere (instanziere) ich Objekte in der main. Deren Methoden kann ich dann aufrufen, die Attribute zugreifen.

Von der Klasse "segel" gibts z.b. zwei Objekte in der main : Gross und Fock. Ich kann jetzt in der main "Gross.setzen()" aufrufen, und "Fock.setzen()" . Als Wert dafür brauche ich in "setzen" einen Inkrementzähler , der in einer ISR an der main geschrieben wird. den kann ich z.b. mit "Gross.Klauinkrement" in der ISR schreiben und in "Gross.setzen()" lesen. Alles prima.

Jetzt möchte ich eine weitere Hierarchieebene einziehen, und die Segelbedienung nicht in der main machen. Ich schreibe ein Objekt "Deckshand", dass die ganze Arbeit tun soll, main setzt bloß noch wenige Befehle an Deckshand. Dazu muß ich "segel" in "deckshand" instanzieren, nicht mehr in der main. (Bildlich : der Skipper rührt die Segel nicht an, er befiehlt bloß)

Aber : das Objekt "Gross", das jetzt in dem Objekt "deckshand" instaziert wurde, kann nicht auf die ISR-Variablen zugreifen !

Als, was tun (außer die Struktur ändern ;-) ??

#7384186
Lesenswert?

Reiner D. schrieb:

Fällt mir echt schwer, das sauber zu beschreiben.

Nö. Ist ganz einfach. Sourcecode in den Anhang. Fertig.

Reiner D. schrieb:

Aber : das Objekt "Gross", das jetzt in dem Objekt "deckshand" instaziert wurde, kann nicht auf die ISR-Variablen zugreifen !

Tut mir leid, als Prosa ist das vollkommen unverständlich.

Und was das mit Objektorientierung zu tun haben soll, verstehe ich auch nicht.

Gast #7384197
Lesenswert?

In welcher Datei eine ISR liegt, spielt keine Rolle. Jedenfalls sind ISR keine C++ Methoden. Wenn ISR auf Objekte zugreifen, brauchst du Zeiger auf diese Objekte, welche für die ISR erreichbar sind.

Für solche global verfügbaren Dinge benutze ich gerne eine Datei die ich global.c nenne und dazu natürlich auch eine global.h die ich dann bei Bedarf inkludieren kann.

OP #7384217
Lesenswert?

Ich probiers mal mit Code. Zuerst eine symbolische main :

//Klassen : #include "segel.h" #include "deckshand.h"

//Objekte : deckshand Matrose1; deckshand Matrose2; segel Fock; segel Gross; segel Besan;

//Variablen usw.

int main(void) { while(1) //endlosschleife (wie bei ner sps) { if (trigger_10hz == 1) //timergesteuerte ausführung { trigger_10hz = 0;
//------Hier spielt die Musik-----------------

1
        Gross.setzen();
2
            
3
        //Irgendwas ...
4
        //--------------------------------------------
5

6

7
    }//ende der 10hz-task in der "while 1" -main-schleife
8
};//ende "while 1" - schleife innerhalb main
9
return 0;

}//ende von main

ISR (PCINT0_vect) //Inkremente aus Gruppe 0 { Gross.Klauinkrement ++ ; }

Im Objekt "Gross" wird die Methode "setzen" aufgerufen. In Methode "setzen" wird das Attribut "Klauinkrement" benötigt. Sowohl das Objekt "Gross" als auch das Objekt "Fock" haben dieses Attribut. Beide sind aus der ISR zugreifbar, ohne sich zu überschreiben.

Insgesamt soll das eine exemplarische Grundstruktur von OO sein. Danach werden Methoden durch Vererbung erzeugt usw, usw ...

Wenn jetzt "segel" in "deckshand" instanziert wird statt in main :

#include "segel.h" segel Grossegel; //Klasse instanzierenn-> Objekt deckshand::deckshand() //Konstruktorlauf { fockfallsollwert=0; //die Fallwinden aus grossfallsollwert=0; besanfallsollwert=0; } void deckshand::segelsetzen() { if (Klauinkrement < 600) { //irgendwas } }

.. dann klappt das nicht, weil das Attribut Klaukinkrement (siehe ISR oben) natürlich nicht zugegriffen werden kann, es gibt in main ja kein Objekt "Gros" mehr. Ich bräuchte : "Matrose1.Gross.Klauinkrement" , aber das ist wohl Quatsch ;-)

OP #7384222
Lesenswert?

Harald K. schrieb:

In C++ wird der Begriff "Methode" nicht verwendet. So etwas heißt dort Funktion, auch wenn es zu einer Klasse gehört.

Da schau her. Zitat Wikipedia :

Was ist eine Methode in C++? Methoden (englisch method oder member function) sind in der objektorientierten Programmierung Unterprogramme in der Form von Funktionen oder Prozeduren, die das Verhalten von Objekten beschreiben und implementieren. Über die Methoden des Objekts können Objekte untereinander in Verbindung treten.

#7384225
Lesenswert?

Wie kann man sich Objekte und ISR gleichzeitig antun ? Aber das Konzept der Objekte wurde verstanden ? Und das Konzept der ISR wurde auch verstanden ? Objekte kapseln Code und zugehoerige Daten. Ein Objekt hat dafuer passende Code Konstrukte. Und jetzt willst du quer hinein pfuschen mit Interrupts ? Lass mal - das wird so nichts.

#7384231
Lesenswert?

Harald K. schrieb:

Auch hier ist die Terminologie kaputt.

Eine Referenz ist etwas anderes als eine Instanz.

Reiner D. schrieb:

Was ist eine Methode in C++?

Oliver S. schrieb:

Schlag mal in deinem C/C++-Buch das Stichwort „extern“ nach.

usw. usf.

Reiner D. schrieb:

Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben.

Was muß ich lernen, um das zu lösen ??

Für kleine 8Bitter die Programmiersprache anpassen? Sonst läuft man wie gesehen schnell in die Falle sich mehr mit Sprachbürokratien denn mit dem eigentlichen Problem herumzuschlagen.

Oliver S. schrieb:

In dem Fall C

oder je nach Programmumfang noch ne Stufe drunter!

#7384240
Lesenswert?

Reiner D. schrieb:

.. dann klappt das nicht, weil das Attribut Klaukinkrement (siehe ISR oben) natürlich nicht zugegriffen werden kann,

Es heißt ja auch Gross.Klauinkrement

es gibt in main ja kein Objekt "Gros" mehr.

Hä? Ja doch. Steht doch da. segel Gross;

Ich bräuchte : "Matrose1.Gross.Klauinkrement" , aber das ist wohl Quatsch ;-)

Ja. Keine Ahnung, wo jetzt der matrose1 herkommt.

Gast #7384243
Lesenswert?

Harald K. schrieb:

In C++ wird der Begriff "Methode" nicht verwendet. So etwas heißt dort Funktion, auch wenn es zu einer Klasse gehört.

Ist doch Scheiß egal. Jeder weiß, was gemeint war. Nach zig Jahren Berufserfahrung mit zahlreichen Programmiersprachen hat man andere Probleme als solche albernen Eitelkeiten.

Gast #7384255
Lesenswert?

Was muß ich lernen, um das zu lösen ??

Klingt der Funktion nach nach einem Task/process-Scheduler. Der Linus hat mal zwischen Januar und september1991 einen solchen für x386 geschrieben und später zum Linux-Kernel erweitert.

Nachlesbar im Link wie im Anhang gezeigt, die direkte Wiedergabe des Links wird von der Forumssoftware blockiert. Seufz ....

https://de?.to/satorutakeuchi/a-brief-history-of-the-linux-kernel-s-process-scheduler-the-very-first-scheduler-v0-01-9e4

? durch v ersetzen

Angehängte Dateien:
OP #7384282
Lesenswert?

Jetzt kam ein Haufen.

Ja, das ist ein Scheduler (wenn wir das gleiche meinen). Aber non-premptive, um sich den ganzen Quatsch mit Deadlock, Race und so zu ersparen. NPRM im Klartext.

Globale Variable (extern ?) sind möglicherweise nicht zielführend, weil ich dann ja für die Attribut eines jeden neuen Objekts neue Variablen brauche. Aber es geht natürlich. Ich denke bloß, da muß es im Konzept eine elegantere Methode geben. Konzeptuell müßte bei der Instanzierung (nicht Referenzierung, sorry) des Objekts irgendwo eine globale Variablenerzeugung möglich sein. Ich sehe auch nicht, wie das mit einem Zeiger geht, wenn wie hier mehrere Objekte die im "Orginal" (der Klasse) gleichen Attribute hat. Aber hier weiß ich sicher viel zu wenig über Zeiger in C.

Ist aber anders formuliert eigentlich meine Frage :

Wie kann ich im OO-Konzept Objektattribute so erzeugen (instanzieren), daß sie von überall (global) zugreifbar sind ?

#7384292
Lesenswert?

Reiner D. schrieb:

Konzeptuell müßte bei der Instanzierung (nicht Referenzierung, sorry) des Objekts irgendwo eine globale Variablenerzeugung möglich sein.

Wie kann ich im OO-Konzept Objektattribute so erzeugen (instanzieren), daß sie von überall (global) zugreifbar sind ?

Kann es sein, dass du gar nicht so richtig weißt, was diese Fachbegriffe alle bedeuten? Ich verstehe jedenfalls nur Bahnhof und diese Aneinanderreihung der Begriffe ergibt für mich wenig Sinn.

Zeig doch einfach einmal ein einfaches(!) minimales(!) Stück Code, was dein Problem zeigt.

OP #7384298
Lesenswert?

Was ist daran so schwer zu verstehen ?

Ich möchte bei Erzeugen eines Objekts eine "Variable" (besser ein "Attribut", wenn die Zahl der Erbsen eine Rolle spielt) generieren, die die Eigenschaften einer globalen hat. Bitte jetzt keine Diskussion über das alte public/private Spiel..

Wenn "extern" das kann, wäre einer so lieb, mir ein Stück Beispielcode zu zeigen ?

#7384299
Lesenswert?

Reiner D. schrieb:

Ich möchte bei Erzeugen eines Objekts eine "Variable" (besser ein "Attribut", wenn die Zahl der Erbsen eine Rolle spielt) generieren

Dein Text ergibt überhaupt gar keinen Sinn.

Das ist das Problem.

Was ist "das Erzeugen eines Objekts"? Ist es der Aufruf des Konstruktors? Was meinst du mit "Attribut"? Was ist "generieren"? Warum setzt du "Variable" in Anführungszeichen. Meinst du was anderes?

#7384305
Lesenswert?

OP #7384310
Lesenswert?

Purzel H. schrieb:

Bei der Instanzierung des Objektes wird die Variable erzeugt. Dann muss man ihr nur noch einen Wert zuweisen.

Was ggf. der Konstruktor tut. Und weil sie in OO eine spezielle Charakteristik hat, wird sie Attribut genannt, um sie von der klassischen Variablen abzuheben. Aber : darum gehts überhaupt nicht. Ich will hier keine Wortkunde betreiben ...

Gast #7384326
Lesenswert?

So geht das

1
#include <iostream>
2
using namespace std;
3

4
int* globalerZeiger;
5

6
class Schiff {
7
    int geschwindigkeit;
8
    
9
public:
10
    Schiff() {
11
        globalerZeiger = &geschwindigkeit;
12
    }
13

14
    ~Schiff() {
15
        globalerZeiger = nullptr;
16
    }
17

18
    int getGeschwindigkeit() {
19
        return geschwindigkeit;
20
    }
21
};
22

23
int main() {
24
    Schiff einSchiff;
25
    *globalerZeiger = 99;
26
    cout << "Geschwindigkeit:" << einSchiff.getGeschwindigkeit() << endl;
27
}
OP #7384332
Lesenswert?

Die static-Deklaration ist es wohl nicht, siehe :

"Static variable in a class:

Static variable in a class is not a part of the subobject of the class. There is only one copy of a static data member shared by all the objects of the class."

Also das friend-Konzept. Ich dachte bisher, das wär was für Functions in namespaces, und mit solchen Dingen hab ich auf den kleinen uP nie zu tun gehabt. Liege ich richtig, wenn ich vermute, daß ein friend-Konstrukt den Zugriff aus einem Objekt auf ein Attribut eines anderen Objekts zuläßt (alles public, oder ?) ? ..Viel zu tun.

Gast #7384334
Lesenswert?

Reiner D. schrieb:

Folgende Situation, selbst erlebt :

Ein promovierter Jurist frägt den Ingenieur nach einem Vortrag. "Was ist denn ein Operationsverstärker ? ".

Eben, der Juristen formuliert eine trollig falsch formulierte Frage und bekommt denoch eine korrekte Anwort.

Hätte der Jursit statt der Frage "Was ist ein Operationsverstärker", die mit der Nennung der Typbezeichnung völlig korrekt beantwortet ist, gebeten "Bitte erklären Sie mir als elektronisch Ungebildeten die Aufgabe und Funktion eines Operationsverstärkers" hätte er mehr Erfolg gehabt.

Aber wer gibt schon zu, da er zu doof für das Thema "Elektronik" ist.

Wer's im Kontext lustig findet, möge lachen ;-)

Das finden nur Kinder die bespasst werden müßen, lustig. Dist Du so eins?

Gast #7384339
Lesenswert?

MaWin O. schrieb:

Das ist ja schon fast Körperverletzung. Es gibt keinen einzigen Grund und keine Entschuldigung so etwas zu tun.

Jetzt kannst du einen besseren Vorschlag machen, wo eine ISR in C die Geschwindigkeit des Schiffes ändert. Denn ich denke, darauf will der TO hinaus.

OP #7384344
Lesenswert?

@ Stefan F.

Ich brauche ne Weile, um deinen Code zu verstehen, sorry. Mein Syntaxvorrat reicht immer genau so weit wie ich zur Lösung von irgendwas brauche, ich hatte nie systematisch C gelernt. (Merkt man ja ;-).

Wenn ichs richtig interpretiere, wird statt des Attributs eine indirekte Adressierung ausgeführt, also ein Pointer benutzt, wie das in C wohl heißt.

Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu welchem Objekt gehören ?

#7384350
Lesenswert?

Reiner D. schrieb:

Liege ich richtig, wenn ich vermute, daß ein friend-Konstrukt den Zugriff aus einem Objekt auf ein Attribut eines anderen Objekts zuläßt (alles public, oder ?)

Ja. Aber eben fordertest du noch:

Reiner D. schrieb:

Bitte jetzt keine Diskussion über das alte public/private Spiel..

Stefan F. schrieb:

Jetzt kannst du einen besseren Vorschlag machen, wo eine ISR in C die Geschwindigkeit des Schiffes ändert. Denn ich denke, darauf will der TO hinaus.

1
ISR()
2
{
3
  schiff.schneller(10);
4
}

Man braucht weder einen Zeiger auf schiff.geschwindigkeit, noch braucht man von außen direkt auf schiff.geschwindigkeit zuzugreifen.

#7384353
Lesenswert?

Reiner D. schrieb:

Syntaxvorrat

Dein was? Schon wieder ein Wort falsch verwendet?

ich hatte nie systematisch C gelernt. (Merkt man ja ;-).

Allerdings. Aber das kannst du ja ändern.

Reiner D. schrieb:

wird statt des Attributs

Das ist kein Attribut. Das ist eine Member-Variable. Ein Attribut ist in C++ etwas anderes. https://en.cppreference.com/w/cpp/language/attributes Du verwendest ständig Worte falsch. Und deshalb versteht dich niemand.

Reiner D. schrieb:

Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu welchem Objekt gehören ?

hä? Wozu soll eine Liste benötigt werden? Wozu sollte das gut sein?

OP #7384355
Lesenswert?

Nur zur Erklärung :

Nein, hat nix mit Schiffsgeschwindigkeiten oder ähnlichem zu tun.

Im Kern geht's um Hierarchisierung von Funktionen. Ich schreibs nochmal als "Prosa", Modellierung ist ja auch ein Bestandteil von OO.

Oberste Ebene : "main" (im Modell : Der Käptn')

erste drunter : Objekte der Klasse "deckshand" : "matrose1", "matrose2"

matrose1 ist eine Instanz von deckshand, die in main instanziert wurde. Voteile : wenn man neue Funktionen will, wird ein neuer matrose instanziert. Methoden von deckshand können vererbt usw. werden.

wieder drunter : Objekte der Klasse "segel". Die werden jetzt in den Matrosen instanziert. Vorteile wie üblich in OO. z.b "fock" oder "gross".

so, jetzt kann ich in "matrose1" die methode "fock.setzen()" aufrufen.

-> Ich will aber in main auf Attribute von "fock" in "matrose" zugreifen !

Gast #7384362
Lesenswert?

Reiner D. schrieb:

Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu welchem Objekt gehören ?

Mein Beispiel funktioniert nur mit einer Instanz des Schiffes. Der MaWin O. hat meinen obigen Vorschlag zu Recht kritisiert. Denn der Sinn von Objekten ist, dass sie ihre Daten Kapseln. Man sollte niemals von außen direkt auf die Attribute der Objekte zugreifen, schon gar nicht über Zeiger an der Programmiersprache vorbei.

Man kann aber die Instanzen der Objekte global erreichbar machen. Zum Beispiel so:

1
#include <iostream>
2
using namespace std;
3

4
class Schiff {
5
    int geschwindigkeit;
6

7
public:
8
    int getGeschwindigkeit() {
9
        return geschwindigkeit;
10
    }
11

12
    void setGeschwindigkeit(int i) {
13
        geschwindigkeit = i;
14
    }
15

16
    void changeGeschwindigkeit(int i) {
17
        geschwindigkeit += i;
18
    }
19
};
20

21
Schiff* schiffe[20];
22

23
// Bei Interrupt wird das erste Schiff verlangsamt
24
void isr() {
25
    schiffe[0]->changeGeschwindigkeit(-1);
26
}
27

28
int main() {
29
    // Erzeuge drei Schiffe
30
    schiffe[0] = new Schiff();
31
    schiffe[1] = new Schiff();
32
    schiffe[2] = new Schiff();
33

34
    // Alle drei Schiffe sind unterwegs
35
    schiffe[0]->setGeschwindigkeit(99);
36
    schiffe[1]->setGeschwindigkeit(99);
37
    schiffe[2]->setGeschwindigkeit(99);
38

39
    // Interrupt simulieren
40
    isr();
41

42
    cout << "Geschwindigkeit erstes Schiff:" << schiffe[0]->getGeschwindigkeit() << endl;
43
    cout << "Geschwindigkeit zweites Schiff:" << schiffe[1]->getGeschwindigkeit() << endl;
44
    cout << "Geschwindigkeit drittes Schiff:" << schiffe[2]->getGeschwindigkeit() << endl;
45
}
Beitrag #7384370 wurde von einem Moderator gelöscht.
Gast #7384377
Lesenswert?

Stefan F. schrieb:

// Erzeuge drei Schiffe schiffe[0] = new Schiff(); schiffe[1] = new Schiff(); schiffe[2] = new Schiff();

Ich sollte dazu noch etwas ergänzen: Diese Zeilen müssen nicht in der main stehen. Du kannst wie gewünscht ein Schiffsbauer-Objekt programmieren, dass die Schiffe baut (mit new erzeugt) und dem Array zuweist.

Anstelle des Arrays könntest du auch drei einzelne globale Variablen verwenden, wenn dir das lieber ist. Aber auf jeden Fall müssen die Zeiger oder die Referenzen auf auf die Schiffe global sein, sonst kommst du innerhalb deiner ISR nicht heran.

Gast #7384387
Lesenswert?

Reiner D. schrieb:

Was lange währt, wird endlich gut. Natürlich lag es an meiner unpräzisen Beschreibung meines Problems.

Ich dachte nur, meine Syntaxerfindung : "Matrose1.Gross.Klauinkrement" wäre ein frommer Wunsch. Daß das in C++ geht, ist überraschend.

1
Schiff erstesSchiff;
2
Schiff* zeigerAufZweitesSchiff;
3

4
int main() {
5
    zeigerAufZweitesSchiff = new Schiff();
6

7
    cout << "Geschwindigkeit erstes Schiff:" << erstesSchiff.getGeschwindigkeit() << endl;
8
    cout << "Geschwindigkeit erstes Schiff:" << zeigerAufZweitesSchiff->getGeschwindigkeit() << endl;
9
}

Oder wenn Geschwindigkeit public ist:

1
Schiff erstesSchiff;
2
Schiff* zeigerAufZweitesSchiff;
3

4
int main() {
5
    zeigerAufZweitesSchiff = new Schiff();
6

7
    cout << "Geschwindigkeit erstes Schiff:" << erstesSchiff.geschwindigkeit << endl;
8
    cout << "Geschwindigkeit erstes Schiff:" << zeigerAufZweitesSchiff->geschwindigkeit << endl;
9
}

Du benutzt "." um direkt auf Eigenschaften deiner Objekte zuzugreifen. Bei Zeigern auf Objekte benutzt du hingegen "->".

Beitrag #7384388 wurde von einem Moderator gelöscht.
Gast #7384406
Lesenswert?

Reiner D. schrieb:

Ich brauche ne Weile, um deinen Code zu verstehen, sorry. Mein Syntaxvorrat reicht immer genau so weit wie ich zur Lösung von irgendwas brauche, ich hatte nie systematisch C gelernt.

Du meinst C++. Vielleicht hilft dir mein Tutorial http://stefanfrings.de/qt_lernen/index.html

Deine folgenden Fragen beziehen sich auf meinen (fragwürdigen) Vorschlag:

1
int* globalerZeiger;
2

3
class Schiff {
4
    int geschwindigkeit;
5

6
  public:
7
    Schiff() {
8
        globalerZeiger = &geschwindigkeit;
9
    }
10
}
11

12
*globalerZeiger = 99

Wenn ichs richtig interpretiere, wird statt des Attributs eine indirekte Adressierung ausgeführt, also ein Pointer benutzt

Ja, in meinem Vorschlag ist int* ein Zeiger auf eine Integer Variable. Und &geschwindigkeit ist die Adresse der Geschwindigkeit im RAM.

Legt der Compiler dann da ne Liste an, welche Adresspeicher (Pointer) zu welchem Objekt gehören ?

Der Zeiger hat initial den Wert 0, was allgemein als "zeigt nirgendwo hin" interpretiert wird. Der Konstruktor des Schiffes setzt den Zeiger auf die Adresse seiner Geschwindigkeits-Variable. Erst nach Ausführung des Konstruktors kann man über den Zeiger auf den Speicher der Variable im RAM zugreifen.

Die letzte Zeile im obigen Code-Fragment heißt: Setze den Speicher auf den der Zeiger zeigt, auf den Wert 99. Dadurch wird effektiv die Variable geschwindigkeit von dem Schiff geändert, weil sie sich genau dort im Speicher befindet, wo der Zeiger hin zeigt.

Unsauber ist daran, dass ich dadurch eine eigentlich private Eigenschaft des Objektes global zugänglich gemacht habe, und zwar nicht nur für lesende Zugriffe, sondern auch noch für schreibende.

#7384471
Lesenswert?

So Singletons sind meistens unschön. Und wenn schon mit C++ abstrahiert werden soll, dann würde ich die Methodenaufrufe auch nicht direkt in der ISR machen. Schöner geht das z.B. mit einer EventQueue die auch zyklische Aufrufe erlaubt. Ein instantiiertes Objekt kann sich dann selber in die Queue eintragen. Methodenaufrufe sind nur etwas tricky, die callbacks brauchen den this pointer und die Adresse der Funktion.

#7384498
Lesenswert?

J. S. schrieb:

Schöner geht das z.B. mit einer EventQueue die auch zyklische Aufrufe erlaubt. Ein instantiiertes Objekt kann sich dann selber in die Queue eintragen. Methodenaufrufe sind nur etwas tricky, die callbacks brauchen den this pointer und die Adresse der Funktion.

Die Sprachkenntnisse des TO liegen irgendwo zwischen Frühgeburt und Analphabet. Da ist dein Vorschlag vielleicht doch etwas verfrüht.

Oliver

#7384523
Lesenswert?

Hmm, na ja, es werden viele Sachen hier durchmischt, glaube ich.

Worum es geht, soweit ich das nachvollziehen kann, ist es, dass der OP ein Objektmodell erzeugen möchte, welches ein Schiffsmodell mit verschiedenen Szenarien beschreibt.

Ein Objekt hat ja grundsätzlich eine Lebenszeit, startend beim Konstruktor und endend beim Destruktor - solange das Objekt 'lebt', hat es Zustand (Membervariablen), deren Inhalt sich im Laufe der Lebenszeit ändern kann. Diese 'Member' sind üblicherweise private und sollten nur über definierte Memberfunktionen/Methoden verändert werden. So die die Theorie.

Singletons bzw. statische Klassen sind im Prinzip ja genau dasselbe, nur dass es eben bloß 1 Exemplar dieser Klasse zur Laufzeit (=1 Objekt) gibt. Ändert fürs Objektmodell eigentlich nicht viel.

Wenn du ein Objekt anlegst/instanziierst, kann das so aussehen, wie Stefan F. das beschrieben hat, mit dem new-Operator instanziiert. Ne andere Variante wäre einfach:

1
class Segel
2
{
3
public:
4
  enum class Status
5
  {
6
     Gerefft = 0,
7
     VollesSegel
8
  };
9

10
  void setzen(enum class Status state )
11
  {
12
     if(m_status != state)
13
     {
14
        m_status = state;
15
        //... auf aenderung etwas ausloesen
16
     }
17
  }
18

19

20
private:
21
  Status m_status;
22
};
23

24
class Kapitaen
25
{
26
 int m_flaschenGrogIntus = 0;
27
public:
28
   
29
   void auftanken()
30
   {
31
      ++m_flaschenGrogIntus;
32
   }
33

34
   void ablassen()
35
   {
36
      if(m_flaschenGrogIntus>0)
37
      {
38
         --m_flaschenGrogIntus;
39
      }
40
   }
41

42
};
43

44
class Schiff
45
{
46
  Segel m_segel;
47
  Kapitaen m_kapitaen;
48

49
public:
50

51
  Schiff()
52
  {}
53

54
  void volleFahrt()
55
  {
56
     m_segel.setzen(Segel::VollesSegel);
57
     m_kapitaen.auftanken();
58
  }
59

60
  void angreifen(Schiff & gegner)
61
  {
62
    gegner.bumm();
63
  }
64

65
  void bumm()
66
  {
67
     m_kapitaen.auftanken();
68
     m_kapitaen.auftanken();
69
     //untergehen
70
  }
71
};
72

73
int main()
74
{ 
75
   Schiff seaMonkey;
76
   Schiff leChuckSchiff;
77
   seaMonkey.volleFahrt();
78
   seaMonkey.angreifen(leChuckSchiff);
79
}

Legst du eine Instanz vom Schiff an (seaMonkey), wird der Konstruktor aufgerufen. Bei der schließenden Klammer } fliegt das Objekt aus dem Scope, die Lebenszeit ist vorbei - der Destruktor wird aufgerufen. Dazwischen kannste Methoden der Klasse aufrufen, wie z.B. volleFahrt, wobei auch gleich der Käptn mitgetankt wird.

In erster Linie erzeugst du hierarchische Abbildung durch Komposition - quasi das große ist die Summe der Teile - im Beispiel enthält das Schiff einen Käptn und ein Segel. Heißt - erzeugst du ein Schiff, wird Segel und Käptn mit erzeugt. Man kann auch Aggregation machen, dann können die Teile auch länger leben als das Schiff.

Mal grob als Idee, hilfreich zum Verständnis sind vielleicht UML Objektdiagramme oder auch ein E/R-Modell.

#7384626
Lesenswert?

So mal abseits der Programmierkenntnisse würde ich darauf tippen, das einfach die verschiedene Sichtweisen zu Problemen führen.

Reiner D. schrieb:

Oberste Ebene : "main" (im Modell : Der Käptn')

Das ist nämlich der komplett falsche Ansatz um deine Objekte zu betrachten.

Die main.c (oder main.cpp) ist deine Welt in der du dich bewegst. In der main.h(pp) musst du alles benennen (nicht definieren) was in der Welt existieren soll. Dabei musst du es nicht unmittelbar machen. Du kannst mit einem #include auch andere Sammlungen von Benennungen, aka andere Headerdateien einbinden.

Deine main.c sollte dann auch nur die Geschehnisse deiner Welt beschreiben. Also wie sie entsteht, dass passiert in der main-Funktion und was sie so macht, das sind die Interruptroutinen. Da deine Welt über die Header weiß was es alles auf ihr gibt solltest du auch darauf zu greifen können. Wenn es richtig von Grundauf OO ist, dann in der Art Schiff.GetMatrose(Kapitän).GebBefehlAn(Steuermann)

Wie viele schon geschrieben habe, mache die mit den Konzepten betraut und male dir einen Bauplan auf ein Stück Papier.

Nebenfrage: welches main meinst du wieder. Du selber schreibst weiter oben das es ja main-Funktion und main.h gibt Die beiden hängen nicht wirklich systematisch zusammen

OP #7384686
Lesenswert?

@Jens :

Syntax ist mir egal, mich interessiert nur das Konzeptuelle.

"Die main.c (oder main.cpp) ist deine Welt in der du dich bewegst. In der main.h(pp) musst du alles benennen (nicht definieren) was in der Welt existieren soll."

In Code::Blocks Projekten gibts gar keine main.h Ich wollte so modellieren wie im Wordbild dargestellt. Die main.cpp ist bei mir das Deck meines Schiffes, auf dem alle Akteure kommunizieren. Sie sind in der #include - Liste mit ihren .h aufgeführt (quasi meine Decksrolle, Besatzungsliste).

Die Objekte gliedern das Konzept sehr schön, man könnte die Arbeit auch gut verteilen, wenn die Schnittstellen sauber definiert sind.

Käptn gibt Befehle an Matrosen, die haben Elemente des Schiffs (Segel, Ruder, Maschine, Navigationsraum...), dort steht die Hardware (Winden, Motor, GPS...).

Leider ist ein Teil der Messtechnik (z.b. die Inkrementgeber der Winden) in ISR (geht wegen Timing nicht anders). Und die ISR sind hier auf main-Ebene. Der Pfeil von ISR zur class segel (eigentlich besser zum Objekt Fock z.B.) ist mein Problem. Aber ich denke mit den Zeigern von Stefan F. wird das.

Konzept schlecht ? (sind ja wohl verschiedene Ansätze möglich...)

Angehängte Dateien:
#7384695
Lesenswert?

Reiner D. schrieb:

an Matrosen, die haben Elemente des Schiffs (Segel, Ruder, Maschine, Navigationsraum...)

Ich finde es äußerst bizarr, dass du eine Komposition von Matrosen und Schiffselementen machst.

Ein natürlicheres Modell wäre eine Komposition aus Schiff + Schiffsteile und eine weitere Komposition der Besatzung. Die Besatzung würde dann per (kurzlebiger) Referenzen auf die Schiffsteile einwirken.

Reiner D. schrieb:

Aber ich denke mit den Zeigern von Stefan F. wird das.

In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern.

#7384705
Lesenswert?

Reiner D. schrieb:

Modellgrundlage ist, wer mit was arbeitet

Ja. Das ist meiner Ansicht nach ein schlechtes Modell.

Komposition sollte IMO eher durch physikalische Zusammenhänge gebildet werden und "arbeitet mit" sollte mit Referenzen gebildet werden. Der Vorteil ist, dass man so sehr viel flexibler ist. Was, wenn ein Matrose mal das Deck schrubben soll? Was, wenn das immer ein anderer Matrose sein soll, weil die Drecksarbeit geteilt wird? Mit einer Komposition ist das nicht abbildbar.

#7384714
Lesenswert?

Reiner D. schrieb:

"schrubben" als Methode in die deckshand-class zu schreiben ist Mist, oder ? (so daß jeder Matrose das kann)

Mal als Konzeptbeispiel:

1
class Deck { ... };
2

3
class Matrose {
4
...
5
   void schrubbe(deck &Deck) {
6
      ...
7
   }
8
};
9

10
int main() {
11
    Deck deck;
12
    Matrose matrose1;
13
    Matrose matrose2;
14

15
    if (/* Montag */) {
16
       matrose1.schrubbe(deck);
17
    } else {
18
       matrose2.schrubbe(deck);
19
    }
20
}

Tippfehler sind absichtlich ;)

OP #7384718
Lesenswert?

J. S. schrieb:

Für eine Rechts oder Linkskurve muss ein bestimmter Ablauf eingehalten werden.

Bei meinem Schiffchen :

Der Käptn will (z.b. wenn der Sender ausfällt, oder ich das Schiff nicht mehr sehe) per Autopilot irgendwohin (oder nach home).

Er frägt den Navigator nach dem Zielkurs, Navigator liest GPS, rechnet PID und kriegt Zielkurs raus.

Er befiehlt dem Rudergänger den Zielwinkel, der liest den Kompass, PID für Sollwinkel.

Daneben befiehlt der Käptn den Matrosen1 bis 3 ihre jeweiligen Segel zu bergen, und dem Maschinisten, den Motor zu starten.

Gast #7384721
Lesenswert?

Reiner D. schrieb:

Ist AVR-GCC kein C++ ?

Die AVR GNU Compiler Collection ist ein Set aus mehreren Compilern, unter anderem (hier relevant) der zu C kompatible C++ Compiler mit Spezieller Unterstützung für AVR Mikrocontroller. Interrupthandler sind im Sprachumfang vom C++ Standard nicht vorgesehen. In C sind sie auch nicht vorgesehen, daher die Mikrocontroller spezifische Erweiterung.

Eine Objekt-Funktion (Methode) kann deswegen nicht als Interrupthandler dienen, weil die Interrupt-Vektoren des AVR Mikrocontrollers

a) nur auf Funktionen, nicht auf Objekte zeigen kann. Die Tabelle müsste für jedes Objekt zwei Zeiger enthalten (Funktion und Daten (this)).

b) schreibgeschützt ist. Objekte, die erst zur Laufzeit erzeugt werden, können sich nicht in die Interrupt-Vektoren eintragen.

MaWin O. schrieb:

In modernem C++ arbeitet man auch gutem Grund praktisch nie mit Zeigern.

Dazu habe ich eine ernst gemeinte Frage: Referenzen sind technisch gesehen auch Pointer, haben lediglich eine andere Syntax. Wie erzeugst du Objekt-Instanzen zur Laufzeit, ohne new und ohne Referenzen/Pointer?

#7384723
Lesenswert?

Stefan F. schrieb:

Dazu habe ich eine ernst gemeinte Frage: Referenzen sind technisch gesehen auch Pointer, haben lediglich eine andere Syntax.

Nein. Das ist nicht nur eine andere Syntax. In C++ gibt es viele verschiedene Arten Objekte zu referenzieren. Klassische Referenzen und auch verschiedene Smartpointer. Mit Rohzeigern haben die alle eigentlich nichts zu tun.

Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach ganz normal auf statisch alloziierte globale Ressourcen zugreifen.

Stefan F. schrieb:

Wie erzeugst du Objekt-Instanzen zur Laufzeit, ohne new und ohne Referenzen/Pointer?

Einfach auf dem Stack?

#7384725
Lesenswert?

Stefan F. schrieb:

Die AVR GNU Compiler Collection ist ein Set aus mehreren Compilern, unter anderem (hier relevant) der zu C kompatible C++ Compiler mit Spezieller Unterstützung für AVR Mikrocontroller.

Was genau soll ein „zu C kompatibler C++ Compiler“ sein? Der erste April war gestern.

Die AVR-gcc-toolchain kommt, wie jeder gcc, mit einem C- und einem C++ -Compiler. Der eine spricht nur vollwertiges C, der andere nur vollwertiges C++. „Kompatibel“ ist das nur in so weit, wie C und C++ gemeinsame Sprachkonstrukte haben.

Oliver

#7384726
Lesenswert?

Stefan F. schrieb:

Eine Objekt-Funktion (Methode) kann deswegen nicht als Interrupthandler dienen, weil die Interrupt-Vektoren des AVR Mikrocontrollers

Richtig. Nicht direkt. Aber:

1
class MyClass {
2
  void handle_irq() {
3
    ...
4
  }
5
}
6

7
MyClass myclass;
8

9
ISR() {
10
  myclass.handle_irq();
11
}

b) schreibgeschützt ist. Objekte, die erst zur Laufzeit erzeugt werden, können sich nicht in die Interrupt-Vektoren eintragen.

Da könnte man Smartpointer verwenden. Aber auf AVR8 ist es wohl eher generell eine schlechte Idee dynamische Objekte anzulegen. Nicht nur in C++. ;)

Gast #7384728
Lesenswert?

MaWin O. schrieb:

Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach ganz normal auf statisch alloziierte globale Ressourcen zugreifen.

Kommt drauf an, was man machen will. Der TO möchte, dass die ISR Eigenschaften seiner Objekt-Instanzen ändert.

Wie erzeugst du Objekt-Instanzen zur Laufzeit, ohne new und ohne Referenzen/Pointer?

Einfach auf dem Stack?

Der Stack verliert beim Verlassen einer Funktion seine Gültigkeit. Mit der Beschränkung verlierst du die Möglichkeit, Objekte innerhalb von Funktionen zu erzeugen und danach außerhalb dieser zu benutzen. Früher oder später brauchst du das aber.

Der TO braucht es. Seine ISR soll auf Objekte zugreifen, die innerhalb einer Objekt-Funktion (Methode) erzeugt wurden.

Aber auf AVR8 ist es wohl eher generell eine schlechte Idee dynamische Objekte anzulegen.

Ich möchte es nicht generell verbieten, aber man sollte sich diese Fälle gut überlegen. Insbesondere wegen der möglichen Fragmentierung des Heap.

Gast #7384731
Lesenswert?

Oliver S. schrieb:

Was genau soll ein „zu C kompatibler C++ Compiler“ sein? Der erste April war gestern.

C++ ist in meinen Augen ein Aufsatz auf C. So habe ich dessen Entwicklung erlebt.

Als Kontrast dazu möchte ich Java nennen, welches keine Funktionen außerhalb von Objekten kennt.

#7384739
Lesenswert?

Stefan F. schrieb:

Aber ich würde auch behaupten, dass man für eine ISR weder Rohzeiger, noch Referenzen, noch Smartpointer braucht. Man kann doch ganz einfach ganz normal auf statisch alloziierte globale Ressourcen zugreifen.

Kommt drauf an, was man machen will. Der TO möchte, dass die ISR Eigenschaften seiner Objekt-Instanzen ändert.

Das widerspricht sich doch gar nicht.

1
class MyClass {
2
public:
3
  void handle_irq() {
4
     eigenschaft++;
5
  }
6

7
protected:
8
  int eigenschaft = 0;
9
}
10

11
MyClass myclass;
12

13
ISR() {
14
  myclass.handle_irq();
15
}

Der Stack verliert beim Verlassen einer Funktion seine Gültigkeit. Mit der Beschränkung verlierst du die Möglichkeit, Objekte innerhalb von Funktionen zu erzeugen und danach außerhalb dieser zu benutzen. Früher oder später brauchst du das aber.

Das ist eine Behauptung. Kannst du auch ein Beispiel liefern, wo ich das unbedingt brauche?

Der TO braucht es.

Das würde ich in Frage stellen.

Seine ISR soll auf Objekte zugreifen, die innerhalb einer Objekt-Funktion (Methode) erzeugt wurden.

Das würde ich als kaputtes Konzept beschreiben, weil die Methode ja per Definition zum ISR-Aufruf nicht läuft. Und damit auch alle Objekte innerhalb die Gültigkeit verlieren, wie du schon richtig erkanntest.

Das kann man nicht einmal mit Rohzeigern hinfrickeln. Das geht einfach nicht.

Gast #7384745
Lesenswert?

MaWin O. schrieb:

Der TO braucht es.

Das würde ich in Frage stellen.

Zumindest will er es so machen. Lass ihn doch! Du kannst von einem Anfänger nicht erwarten, die hohe Kunst der C++ Programmierung so zu beherrschen, wie einer, der das jahrelang studiert hat.

Auch Anfänger können damit gut funktionierende Sachen hinbekommen - auch wenn sich dem Akademiker dabei die Fußnägel hoch rollen. Ich sage nur: Arduino.

#7384749
Lesenswert?

Stefan F. schrieb:

Zumindest will er es so machen. Lass ihn doch!

Ich lasse jeden das tun, was er will. Keine Angst. :)

Du kannst von einem Anfänger nicht erwarten, die hohe Kunst der C++ Programmierung so zu beherrschen, wie einer, der das jahrelang studiert hat.

Das tue ich auch nicht. Ganz im Gegenteil. Das ist ja der Grund, weshalb ich überhaupt hier Antworte. Ich möchte Anstöße in andere Richtungen geben.

Auch Anfänger können damit gut funktionierende Sachen hinbekommen

Das bestreitet ja auch niemand. Man kann auch in Assembler programmieren und alles funktioniert. Man kann auch C schreiben (Rohzeiger nutzen) und das mit einem C++-Compiler übersetzen. Man braucht auch keine Smartpointer und Referenzen zu benutzen und kann trotzdem alles in einen funktionsfähigen Zustand bekommen. Geht alles. Aber das schien mir jetzt nicht die Intention des Threaderstellers zu sein.

Gast #7384751
Lesenswert?

MaWin O. schrieb:

Du solltest dir unbedingt man etwas >= C++11 anschauen. Es lohnt sich.

Wohl kaum. In meinem Beruf sind ganz andere Programmiersprachen angesagt, da will niemand mehr etwas von C++ hören. Die Sprache ist nur noch für mein Hobby (Mikrocontroller) am Rande neben C ein bisschen interessant.

Mag sein, dass die Sprache im Laufe vieler Jahre allmählich besser geworden ist. Aber sie ist auch zusammen mit der Generation ihrer Entwickler gealtert. In 20 Jahren wenn meiner-einer in Rente geht, arbeitet damit kein Mensch mehr.

Also anstatt ständig den Neuen Aspekten der Sprache hinterher zu laufen, während ich alte Projekte pflegen muss die das eh nicht nutzen können/sollen, lerne ich doch lieber die neuen Programmiersprachen, mit denen die Kollegen links und rechts neben mit erfolgreich Geld für die Firma verdienen. Sonst bin ich nämlich schneller raus aus dem Geschäft, als das Renten-Eintrittsalter vorsieht.

OP #7384756
Lesenswert?

@Stefan :

no pain, no gain. So eine Lernkurve tut weh ...

Also für Doofe :

Ganz oben, in der main :


int* Fallinkrement;

ganz unten, in der class segel.cpp :


int Fallinkrement; segel::segel() { Fallinkrement = &Fallinkrement;

Im Konstruktorlauf wird dem Objekt ein Zeiger zugeordnet (symbolisch (!!) quasi bei Objekt Fock also "Fock.*Fallinkrement" : Zeiger Fallinkrement, der dem Objekt Fall zugeordnet ist)

und jetzt in der ISR :

Fock.*Fallinkrement ++ ;

Hab ich jetzt ein Syntaxproblem, oder hab ich das Zeiger-Konzept noch nicht verstanden ?

Im Kern stört bei mir, dass jedes Segel 3 Taue hat, die jeweils gleich heißen (Fall, Klau, Piek). Und die Auffächerung in Gross.Piek und Besan.Piek geschieht ja erst bei Objekterzeugung. In " int* " gibts die noch nicht.

#7384758
Lesenswert?

Stefan F. schrieb:

Wohl kaum. In meinem Beruf sind ganz andere Programmiersprachen angesagt, da will niemand mehr etwas von C++ hören.

Ja gut. Dann verstehe ich allerdings nicht, warum du hier Ratschläge zu C++ gibst. Für mich gehört es dazu, dass man auf der Höhe der Zeit ist, wenn man Ratschläge gibt.

Die Sprache ist nur noch für mein Hobby (Mikrocontroller) am Rande neben C ein bisschen interessant.

Das mag in deiner Blase stimmen. Das ist aber (leider) ganz und gar nicht die Realität.

Mag sein, dass die Sprache im Laufe vieler Jahre allmählich besser geworden ist.

C++ hat sich nicht nur "allmählich" entwickelt, sondern hat riesige Sprünge in den letzten 15 Jahren gemacht. Das ist nun eine vollkommen neue Sprache, die noch rückwärtskompatibel zu 90er-Jahre-C++ ist. (Zu C war C++ noch nie vollständig rückwärtskompatibel)

Aber sie ist auch zusammen mit der Generation ihrer Entwickler gealtert. In 20 Jahren wenn meiner-einer in Rente geht, arbeitet damit kein Mensch mehr

Sportliche Vorhersage. Ich hoffe, dass du recht behältst. Ich befürchte aber, dass es nicht so sein wird.

Gast #7384763
Lesenswert?

Reiner D. schrieb:

Fock.*Fallinkrement ++ ;

So wäre es richtig:

*Fallinkrement++

Du willst in der ISR auf den globalen Zeiger "Fallinkrement" zugreifen, nicht auf das Attribut der Instanz der "segel" Klasse. An dieser Stelle ist es unvorteilhaft, dass die globale Variable genau so heißt, wie das Attribut der Klasse. Nenne die Variable z.B. "FallinkrementPtr", dann wird es vielleicht klarer.

OP #7384764
Lesenswert?

Und wenn schon gerätselt wird ob meiner Intention : Das Schiffchen krieg ich auch ohne Objekte zum fahren, das ist nicht das Thema. Es geht ums Lernen, hier insbesonders um Konzepte in OO. Für UML bin ich aber leider zu faul.

Wenn hier einer was von SPS versteht : so wie Lasal zum Beispiel, das fand ich konzeptuell extrem spannend. Brauchen tu ich's nicht.

Brauchen tu ich gar nix, hab die Rentengrenze längst überschritten :-))

OP #7384765
Lesenswert?

Stefan F. schrieb:

*Fallinkrement++

Es gibt aber drei Fallinkremente. Je eines vom Inkrementgeber an Fockfallwinde, Grossfallwinde und Besanfallwinde.

Wenn ich nur Objekte in main nutze (die Matrosen also quasi an Deck mitreden lasse) werden die durch Fock.Fallinrement, Gross.Fallinkrement usw. sauber unterschieden, wie es Attribute von Objekten eben tun.

Habe ich dich falsch verstanden, daß ich einen Zeiger im Konstruktorlauf machen kann, der dann dem Objekt zugeordnet ist ?

Gast #7384768
Lesenswert?

MaWin O. schrieb:

Dann verstehe ich allerdings nicht, warum du hier Ratschläge zu C++ gibst. Für mich gehört es dazu, dass man auf der Höhe der Zeit ist, wenn man Ratschläge gibt.

OK, kann ich nachvollziehen.

MaWin O. schrieb:

das Zeiger-Konzept

Bitte trenne dich davon. Es gibt hier keinen einzigen Grund einen Zeiger zu verwenden.

Ja dann gebe ihm doch ein besseres Beispiel, dass er umsetzen kann!

#7384769
Lesenswert?

Das ist schon der richtige Weg an solchen Übungsaufgaben zu lernen.

Solange das ganze Schiff und seine Besatzung statisch sind kann man alles global anlegen und braucht keine Zeiger. Wenn Segel statisch angelegt wird und den Fallinkrement Zeiger setzt, dann kann in der ISR auch gleich direkt auf das Objekt zugegriffen werden. Wie von MaWin O schon gezeigt.

Interessant wird es wenn das ganze dynamisch wird, das Schiff z.B. aus einer Konfigurationsdatei zusammengesetzt wird. Dann spielt das OO Konzept seine Stärken aus.

#7384777
Lesenswert?

Stefan F. schrieb:

Ja dann gebe ihm doch ein besseres Beispiel, dass er umsetzen kann!

Habe ich doch bereits.

Beitrag "Re: C++ Objektorientierung ?"

So geht das. Damit kann man auch alle Kompositionen abbilden.

MyClass kann natürlich Instanzen von anderen Klassen enthalten.

1
class MyClass2 {
2
public:
3
  void handle_irq2() {
4
     eigenschaft++;
5
  }
6

7
protected:
8
  int eigenschaft = 0;
9
};
10

11
class MyClass1 {
12
public:
13
  void handle_irq1() {
14
     myclass2.handle_irq2();
15
  }
16

17
protected:
18
  MyClass2 myclass2;
19
};
20

21
MyClass1 myclass1;
22

23
ISR() {
24
  myclass1.handle_irq1();
25
}
#7384778
Lesenswert?

In main wird nur ein Schiff instanziiert, main ist nur der Lebensraum für Objekte. Das Schiff hat Kapitän, Rudergänger, Matrose. Jetzt muss man überlegen was diese sein sollen, so wie du es wolltest sind es Dienstleister die etwas ausführen können (Methoden). Das Schiff hat auch verschiedene Segel oder Motoren, das sind auch Objekte die ein Schiff hat. Diese kann man auch statisch anlegen weil sie ja fest zum Schiff gehören. Wenn ein Matrose jetzt ein Segel setzen soll, dann muss man ihm auch sagen welches. Das gross, besan usw. statisch angelegt wurden, können diese als Referenz übergeben werden. Das sind auch Zeiger, aber die werden nicht dynamisch angelegt und können damit nicht nullptr sein, das macht den Umgang angenehmer. Kann dann aber nicht dynamisch zusammengesetzt werden.

1
class Segel {
2
}
3

4
class Matrose {
5
  setzeSegel(Segel &segel);
6
}
7

8
class Schiff {
9
  Matrose hein;
10
  Matrose pit;
11

12
  Segel besan;
13
  Segel gross;
14
}
15

16
Schiff.hein.setzeSegel(besan);
17
Schiff.pit.setzeSegel(gross);

so grob.

#7384786
Lesenswert?

MaWin O. schrieb:

Dann spielen Smartpointer ihre Stärken aus.

ja, ist mMn aber eine Feinheit die jetzt für ein Modell keine Rolle spielt. Die Smartpointer sollen ja z.B. die Speicherleck Probleme entschärfen. In C gibts malloc/free, es ist einfach die nicht balanziert aufzurufen. Ich denke dem TO fehlt der Unterschied Zeiger und Referenz bzw. die Anwendung dieser.

Gast #7384788
Lesenswert?

Reiner D. schrieb:

Es gibt aber drei Fallinkremente.

Folglich brauchst du drei Zeiger (oder Referenzen), die jeweils direkt auf die gewünschten Attribute zeigen, oder auf die Objekte, welche die Attribute enthalten.

Ich möchte daran erinnern, dass man eigentlich nicht an der Programmiersprache vorbei direkt auf Attribute der Objekte zugreifen soll. Außerdem sind diese drei Winden Bestandteil eines Schiffes, also genügt es, global auf das eine Schiff zu zeigen oder zu referenzieren:

Mit Referenzen:

1
class Winde {
2
  public:
3
    int fallinkrement;
4
};
5

6
class Schiff {
7
  public:
8
    Winde fockfallwinde;
9
    Winde grossfallwinde;
10
    Winde besanfallwinde;
11
};
12

13
Schiff schiff;
14

15
ISR whatever() {
16
    schiff.fockfallwinde.fallinkrement++;
17
    schiff.grossfallwinde.fallinkrement++;
18
    schiff.besanfallwinde.fallinkrement++;
19
}

Oder mit Zeigern und dynamischer Speicherverwaltung (bei Mikrocontrollern mit Fallstricken behaftet):

1
class Winde {
2
  public:
3
    int fallinkrement;
4
};
5

6
class Schiff {
7
  public:
8
    Winde* fockfallwinde;
9
    Winde* grossfallwinde;
10
    Winde* besanfallwinde;
11
    
12
    // Konstruktor
13
    Schiff() {
14
        fockfallwinde = new Winde();
15
        grossfallwinde = new Winde();
16
        besanfallwinde = new Winde();
17
    }
18
    
19
    // Destruktor
20
    ~Schiff() {
21
        delete fockfallwinde;
22
        delete grossfallwinde;
23
        delete besanfallwinde;
24
    }
25
};
26

27
Schiff* schiff;
28

29
int main() {
30
    schiff = new Schiff();
31
}
32

33
ISR whatever() {
34
    schiff->fockfallwinde->fallinkrement++;
35
    schiff->grossfallwinde->fallinkrement++;
36
    schiff->besanfallwinde->fallinkrement++;
37
}
Gast #7384797
Lesenswert?

Stefan F. schrieb:

Ich möchte daran erinnern, dass man eigentlich nicht an der Programmiersprache vorbei direkt auf Attribute der Objekte zugreifen soll.

Jetzt eine Variante mit indirekten Zugriffen über Objektmethoden, was ich viel sauberer finde:

1
class Winde {
2
    int fallinkrement;
3
  
4
  public:
5
    void ändereIncrement(int wert)  {
6
        fallinkrement = fallinkrement+value;
7
    }
8
};
9

10
class Schiff {
11
    Winde fockfallwinde;
12
    Winde grossfallwinde;
13
    Winde besanfallwinde;
14
  
15
  public:
16
    void ändereIncrementDerWinden(int wert) {
17
        fockfallwinde.ändereIncrement(wert);
18
        grossfallwinde.ändereIncrement(wert);
19
        besanfallwinde.ändereIncrement(wert);        
20
    }
21
    
22
    Winde getFockfallwinde() {
23
        return fockfallwinde;
24
    }
25
    
26
    Winde getGossfallwinde() {
27
        return grossfallwinde;
28
    }
29
    
30
    Winde getBesanfallwinde() {
31
        return besanfallwinde;
32
    }
33
};
34

35
Schiff schiff;
36

37
ISR whatever() {
38
    schiff.ändereIncrementDerWinden(+1);
39
}
40

41
// oder:
42

43
ISR whatever2() {
44
    schiff.getFockfallwinde().ändereIncrement(+1);
45
    schiff.getGossfallwinde().ändereIncrement(+1);
46
    schiff.getBesanfallwinde().ändereIncrement(+1);
47
}

An den MaWin O hätte ich die Bitte, dieses Beispiel auf die neuen besseren Features von C++ 11 zu heben, die mir nicht bekannt sind. Dann müssten wir zu einem guten Schluss kommen, denke ich.

Gast #7384807
Lesenswert?

J. S. schrieb:

Ein Objekt 'Winde' statt 'Segel' wie Stefan schrieb passt besser. Klasse Winde kann gleich sein für die Segel, als Segel würde dann ein enum { gross, besan, fock} reichen.

Ja sorry, ich habe von Schiffen absolut keine Ahnung, deswegen sind meine Beispiele diesbezüglich vielleicht etwas holprig.

#7384818
Lesenswert?

Stefan F. schrieb:

Ja sorry, ich habe von Schiffen absolut keine Ahnung, deswegen sind meine Beispiele diesbezüglich vielleicht etwas holprig.

ich auch nicht, im Detail wird es irgendwann Geschmacksfrage und mehrere Lösungen sind möglich. Wenn die Winden unterschiedliche Eigenschaften haben, dann können das verschiedene Objekte sein. Oder eine Basisklasse und die Varianten sind Ableitungen. Möglichkeiten gibt es viele.

Das dynamisch zu machen wäre wie genannt z.B. das Schiff aus einer Konfigdatei zu erstellen. Schönes Beispiel dafür ist 3D Drucker SW Marlin vs. Smoothieware: Marlin hat config in defines und Änderungen müssen neu kompiliert werden, Smoothie kann config aus Datei lesen und zur Laufzeit Pins zuordnen.

OP #7384821
Lesenswert?

Hab ich auch so probiert, und jetzt liegts wohl an meinem C-Gestammel :

class segel { public : int FallInkrement; };

class deckshand { public : segel Fock; segel Besan; };

In der main :

deckshand Matrose;

In der ISR darunter :

ISR(..) { Matrose.Fock.FallInkrement ++; }

nix geht, Compilerfehler hier : Matrose.Fock.FallInkrement ++ ;

#7384824
Lesenswert?

sieht nicht verkehrt aus. Üblicherweise schreibt man die Klassen groß, die Instanzen klein. Und zwischen Variable und ++ kein Leerzeichen, ist kein Fehler, sieht aber blöd aus.

Matrose muss global über der ISR angelegt sein. Wie ist die Fehlermeldung?

Gast #7384827
Lesenswert?

J. S. schrieb:

sieht nicht verkehrt aus

Finde ich auch. Bei mir compiliert das, wenn ich "ISR(..)" durch "void test()" ersetze, das liegt aber daran, dass ich mein Testprojekt als "Linux Desktop Anwendung" angelegt habe, statt für AVR.

Reiner D. schrieb:

nix geht, Compilerfehler hier : Matrose.Fock.FallInkrement ++ ;

Kann ich so nicht nachvollziehen. Zeige die ganze Fehlermeldung oder hänge dein Projekt in compilierbarer Form an, so dass wir den gleichen Fehler bekommen, wie du.

OP #7384888
Lesenswert?

Jetzt kapier ich erst, was du meinst. Die Datei main.cpp (in der auch die ISR enthalten sind), und die main, in der die Endlosschleife zur Programmausführung läuft.
Ich war vermutlich ungenau mit der Bezeichnung ...

Ich hab das C::B - Projekt gezippt und angehängt. Macht euch aber bitte nicht zuviel Arbeit.

Fehlermeldung : main.cpp|138|error: 'class deckshand' has no member named 'Gross'|

Angehängte Dateien:
#7384925
Lesenswert?

Hallo,

1
Fehlermeldung :
2
main.cpp|138|error: 'class deckshand' has no member named 'Gross'|

Dafür musst du nur in die deckshand.h reinschauen. Gibt es einen Member namens "Gross"? Nein. Du kannst mit deinen Objekten nur Member und Methoden verwenden die public zur Verfügung stehen. Wenn das deine eigenen Klassen sind solltest du das Wissen.

Selbst wenn du das

1
Matrose.Gross.KlauInkrement ++ ;
2
Matrose.Besan.KlauInkrement ++ ;

korrigierst auf

1
Matrose.KlauInkrement++ ;
2
Matrose.KlauInkrement++ ;

gibt es keinen Member namens "KlauInkrement". Weil Matrose ist ja eine Instanz von deckshand.

Fock, Gross und Besan sind Objekte von segel. Die können nur auf public von segel zugreifen.Hier steckt auch der Member KlauInkrement drin. Wahrscheinlich meinst du

1
Gross.KlauInkrement++ ;
2
Besan.KlauInkrement++ ;

Hier ist einfach zu viele Copy & Paste im Spiel. Erschwerend kommt hinzu das Gewürfel mit Groß- und Kleinschreibung. Schreibe Klassennamen Anfangs Groß und Member und Methoden Anfangs Klein. Zudem KlauInkrement unglücklich ist. Was machst beim Dekrementieren dieser Variablen?

Gast #7384928
Lesenswert?

Reiner D. schrieb:

class deckshand' has no member named 'Gross'

So ist es. In der Datei deckshand.h gibt es kein Gross. Wenn du auf ein Gross in deckshand zugreifen willst, muss es dort existieren.

Folgende Zeilen sind ähnlich fehlerhaft, das zeigt mir meine IDE (Qt Creator) schon vor dem Compilieren direkt im Texteditor an:

Matrose.Gross.KlauInkrement ++ ; Matrose.Besan.KlauInkrement ++ ; Matrose.Fock.FallInkrement ++ ; Matrose.Gross.PiekInkrement ++ ; Matrose.Besan.PiekInkrement ++ ;

Matrose ist eine Instanz von deckshand. Deckshand enthält weder ein Gross, noch ein Besan, noch ein Deckshand.

KlauInkrement, PiekInkrement sind FallInkrement sind Attribute der Klasse segel. In deckshand.cpp gibt es drei globale (!) segel mit Namen Fock, Gross, und Besan. Diese sind also nicht Bestandteil von deckshand sondern davon völlig losgelöst. Du musst die Segel in die Klasse deckshand verschieben. Siehe Anhang.

Angehängte Dateien:
OP #7384934
Lesenswert?

Stefan F. schrieb:

Du musst die Segel in die Klasse deckshand verschieben. Siehe Anhang.

Ich habe versucht, deine Struktur :

class Winde { public: int fallinkrement; }; class Schiff { public: Winde fockfallwinde; Winde grossfallwinde; Winde besanfallwinde; }; Schiff schiff; ISR whatever() { schiff.fockfallwinde.fallinkrement++; schiff.grossfallwinde.fallinkrement++; schiff.besanfallwinde.fallinkrement++; }

...auf die Meine zu übertragen.

Winde wird segel, schiff wird deckshand. In der ISR dann die entsprechenden Angabe.

Oh weh, ich kapier's nicht ...

Gast #7384935
Lesenswert?

Weiter oben hat jemand bemängelt, dass hier das Schiff und die Matrosen zu sehr miteinander vermischt werden. Da hat er wohl Recht.

Die Matrosen sollten auf/mit dem Schiff arbeiten, aber nicht Bestandteil des Schiffes sein. Ebenso ist das Schiff kein Körperteil der Matrosen.

Das sollte man nochmal gründlich umstrukturieren.

#7384938
Lesenswert?

Hmm deine Segel sind ja auch eigenschändig und schwirren irgendwo in deiner Welt herum.

Wenn du die Segel als Objekte deines Matrosen haben willst, dann solltest du das auch machen.

Das in deckshand.cpp

1
segel Fock;
2
segel Gross;
3
segel Besan;

muss dazu in deine Klasse deckshand hinein. also in deckshand.h

1
class deckshand
2
{
3
[.. hier dein ganzer anderer Kram]
4

5
segel Fock;
6
segel Gross;
7
segel Besan;
8
}

Aber man sollte auf Klassenmember nur über Methoden zu greifen. Also alles das was du da drin hast, sollte private sein. Und nur die Methoden sollten public sein.

Wie schon gesagt, OO heißt auch dass man sich Gedanken über den Blick auf seine Welt macht. ;-)

[hui, sind hier einige schnell]

Gast #7384940
Lesenswert?

Reiner D. schrieb:

Oh weh, ich kapier's nicht

Anbei die korrigierten Dateien.

Anderes Thema: Füge bei Gelegenheit Include Guards in alle deine Header Dateien ein, damit sie keine Probleme machen, wenn sie mehrfach eingebunden werden. Beispiel:

schweinesteak.h

1
#ifndef SCHWEINESTEAK_H
2
#define SCHWEINESTEAK_H
3

4
class Schweinesteak {
5
    ...
6
}
7
#endif /* von SCHWEINESTEAK_H */
Angehängte Dateien:
#7384959
Lesenswert?

Stefan F. schrieb:

Weiter oben hat jemand bemängelt, dass hier das Schiff und die Matrosen zu sehr miteinander vermischt werden. Da hat er wohl Recht.

Definitiv.

Die Matrosen sollten auf/mit dem Schiff arbeiten, aber nicht Bestandteil des Schiffes sein. Ebenso ist das Schiff kein Körperteil der Matrosen.

Richtig, das Schiff hat mehrere Matrosen und ein Matrose hat maximal ein Schiff. Die können aber wechseln, dann hin und wieder geht so ein Matrose über Bord und muß im nächsten Hafen durch einen neuen ersetzt werden.

Das sollte man nochmal gründlich umstrukturieren.

Ähnlich ist es mit den Aufgaben der einzelnen Matrosen. Die können auch nicht statisch verteilt werden, denn mitunter werden auch erfahrene Segler seekrank, verletzen sich, oder fallen anderweitig aus. Und wer Törns über längere Strecken fährt, braucht irgendwann einen Wachwechsel... auch dann müssen die Aufgaben neu verteilt werden.

#7384962
Lesenswert?

Alles, was hir bisher geschrieben wurde, sind die absoluten Basics von OOP - eigentlich nicht mal das.

Ich steige mal an anderer Stelle: was soll denn die Klasse i2c modellieren? Ok, die TWI-Schnittsteller als I2C. Aber was erwartest Du von dem Konstruktor. Was passiert, wenn Du mehr als i2c-Objekt erzeugts? Das ist übrigens bei allen Deine HW-Abstraktionen so.

OP #7384966
Lesenswert?

@Stefan (und die anderen Konstruktiven) :

Zuerst : DANKE !!

Beim Einbau deines Codes gabs zunächst Probleme, weil Code::Blocks sich daran stört, daß die Klasse und ein Attribut beide "segel" heißen. Kein Problem, Attribut in "segelbefehl" umbenannt.

Läuft immer noch nicht. Die Definitionszeile "class segel" wird bemängelt : segel.h|1|error: redefinition of 'class segel'|

Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. Wieso ? Die include-Zeile ist doch keine Definition der class segel, oder ?

Also : jetzt ist der Compiler zufrieden. Hätte ich ohne eure Hilfe so nicht hingekriegt. Und vor Allem : sowohl über Modellierung als auch über Pointer viel gelernt !!

OP #7384971
Lesenswert?

Wilhelm M. schrieb:

Alles, was hir bisher geschrieben wurde, sind die absoluten Basics von OOP - eigentlich nicht mal das.

Das ist mir klar. Vor langer Zeit war das mal ein Versuch, die grundlegendsten Basics von Objektorientierung auszuprobieren. Im Kern sollten nur die Begriffe : Klasse, Objekt, Methode, Attribut am Beispiel genutzt werden, völlig ohne Mdellierung usw...

So wie :

Klasse ist Obst Objekt ist Apfel Methode ist faulen Attribut ist Farbe (Wert ist rot)

Na ja, und viel weiter bin ich dann in der Anwendung auch nicht gekommen. Ich hab zwar mit Lasal und Codesys automatisiert und ein paar solche Modellprojekte programmiert, aber im strikt low(est) level.

Bin aber eben auch kein Programmierer ...

Gast #7384973
Lesenswert?

Reiner D. schrieb:

Läuft immer noch nicht. Die Definitionszeile "class segel" wird bemängelt : > segel.h|1|error: redefinition of 'class segel'| Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. Wieso ?

Weil die

Stefan F. schrieb:

Include Guards

fehlen.

Die include-Zeile ist doch keine Definition der class segel, oder ?

Die include Zeile nicht, aber der Inhalt der Datei die du an dieser Stelle includierst. Bevor dein Quelltext compiliert wird, wird die Zeile

#include "segel.h"

durch den Inhalt der genannten Datei ersetzt. Du inkludierst aber auch

#include "deckshand.h"

welche wiederum

#include "segel.h"

includiert. Nun hast du den Inhalt der Datei segel.h zweimal in main.cpp eingefügt. Man kann halt nicht zwei (oder mehr) Klassen mit gleichem Namen haben.

#7384978
Lesenswert?

Reiner D. schrieb:

Wenn ich jetzt "#include segel.h" aus der main nehme, gehts. Wieso ? Die include-Zeile ist doch keine Definition der class segel, oder ?

Wie der Stefan dir vorgeschlagen hat solltest du deine Header mit include Guards versehen.

Ja die include-Zeile erzeugt eine Definition der class segel jedesmal wenn sie includiert wird.

wenn deine include.h so aussieht:

1
class segel
2
{
3
[irgendwas]
4
}

dann wird genau dieser Text bei jedem #inculde segel.h eingefügt. Also im einfachsten Fall wird aus:

1
#include "segel.h"
2
[irgendwas anderes]
3
#include "segel.h"

folgendes:

1
class segel
2
{
3
[irgendwas]
4
}
5
[irgendwas anderes]
6
class segel
7
{
8
[irgendwas]
9
}

also füge in deiner segel.h ein

1
#ifdef SEGEL_INCLUDE
2
#define SEGEL_INCLUDE
3

4
class segel
5
{
6
[irgendwas]
7
}
8
#endif // ende von SEGEL_INCLUDE

Damit verhinderst du dass es mehrmals eingefügt wird Das sind aber absolute Basics in der ganzen C-Welt

Gast #7384983
Lesenswert?

Ich kann dir auch nur dringend empfehlen, die Programmiersprache auf einem PC zu lernen/üben.

Mikrocontroller legen da noch einiges an Komplexität oben drauf und sind schwerer zu debuggen. Es ist gut, wenn man die Sprache dann schon in den Grundzügen verstanden hat und wenigstens ein bisschen Erfahrung gesammelt hat.

Du könntest z.B. mein Tutorial durch gehen, und danach ein Program,m schreiben, dass ein Schiff auf den Bildschirm malt. Natürlich indem du es schön aus Objekten zusammen setzt. Du wirst dabei viel lernen.

Siehe http://stefanfrings.de/qt_lernen/index.html

OP #7384984
Lesenswert?

Sheeva P. schrieb:

Bitte beachte Stefans Ausführungen zum Thema "Include Guards"

Im Eifer des Gefechts vernachlässigt. Hab jetzt erst mal nachgelesen, was das tut.

Bisher hab ich diese Zeilen immer aus neuen class-Definitionen rausgelöscht, weil ich bloß Code haben will, den ich auch verstehe. Rein zufällig gabs bisher damit keine Probleme. Conclusio : nochmal was gelernt !

Gast #7384986
Lesenswert?

Reiner D. schrieb:

Klasse ist Obst Objekt ist Apfel

Schon falsch.

Apfel ist auch eine Klasse, und zwar von Obst abgeleitet. Das Bild zeigt drei Instanzen von der Klasse Apfel, oder anders gesagt, drei Objekte oder drei Ausprägungen.

Ein Objekt ist ein Ding, das man erzeugen, anfassen und benutzen kann. Eine Klasse beschreibt nur die Eigenschaften einer Klasse von Objekten, ist aber keine konkrete Ausprägung.

Angehängte Dateien:
OP #7384987
Lesenswert?

Stefan F. schrieb:

Siehe http://stefanfrings.de/qt_lernen/index.html

Ein Traum. Kleiner bescheidener Satz : Ihr würdet nicht glauben, wie weit man mit so einer Murkserei kommt. Hab bisher noch alles zum Laufen gekriegt, aber (wichtig !) nie in professionellem (!) Kontext von Softwareentwicklung. Ich sehe das wie meinen Fernseher : da kapier ich 90% vom Menü auch nicht

#7384989
Lesenswert?

Veit D. schrieb:

Korrektur. Segel als Klassenname sollte Groß geschrieben werden.

Hallo,

Hinweis am Rande. Verwende gleich pragma in den Headerfiles.

1
#pragma once
2
 
3
class Segel
4
{
5
   // ... irgendwas etwas sinnvolles ...
6
}

Ansonsten empfehle ich Reiner sich nochmal im Kleinen mit Klassen zu beschäftigen. Man sieht ja das du in deinen eigenen Klassen nicht durchblickst. Nochmal paar Schritte zurückgehen und den Aufbau überdenken.

OP #7384990
Lesenswert?

Hatte ich irgendwann im PHP-Zusammenhang zitiert :

Classes are nothing without objects! We can create multiple objects from a class. Each object has all the properties and methods defined in the class, but they will have different property values. $apple and $banana are instances of the class Fruit

Auch "godfather of education", (die Uni Harvard), nimmt dieses Beispiel in der Einführungsvorlesung "Objektorientierung"

Gast #7384994
Lesenswert?

Reiner D. schrieb:

Ihr würdet nicht glauben, wie weit man mit so einer Murkserei kommt

Oh doch. Ich (bzw mein Chef) hat damit gut Geld verdient.

Ich sage immer: Softwareentwicklung ist wie ein Adventure spiel. Zuerst muss man herausfinden, was überhaupt machen soll, was das Ziel ist. Dann muss man heraus finden, wie man da hin kommt. Dabei macht man viele Fehler, manche mehrfach. Und wenn man es dann am Ende geschafft hat, kommt schon das nächste Projekt mit neuen Herausforderungen.

Beitrag #7384998 wurde von einem Moderator gelöscht.
#7385013
Lesenswert?

Das Konzept ist ja auch wirr ;-)

Wenn du eine Simulation schreiben wolltest und Kapitän, Matrosen usw wären Spielfiguren dann wären Klassen dafür sinnvoll. Aber für ein Modellschiff mit einem AVR zu steuern ???

Du bist der Kapitän mit deiner Fernsteuerung in der Hand, der Empfänger mit dem AVR sind deine Offiziere die deine Befehle als Aktionen an die Matrosen(Servo) weiter geben.

OP #7385040
Lesenswert?

Weit gefehlt ! Der AVR ist sogar eigentlich zu klein, mir gehen sowohl die externen Interrupts (deshalb die PCINT) als auch die Timer aus, ich muß sogar Timer multiplexen... Wenn ichs nochmal bauen würde, würde ich die Navigation und den Skipper wohl mit einem Raspi unter Python machen, zwecks der Gaudi.

Das Ding soll :

Ferngesteuert fahren (na ja, kein Ding, da hast du recht..). Alle Segel bergen und setzen können (kann kaum ein Modellboot). Auf Wunsch viele Waypoints (GPS-Koordinaten) unter Motor anfahren können mit FPV, also einer Funkkamera, die zeigt, was da zu sehen ist. Bei Senderausfall (oder einfach ausschalten) automatisch Segel bergen und zum Ausgangspunkt ("home") unter Motor zurückfahren.

Die härteste Forderung, nämlich unter Segeln Waypoints anzufahren, habe ich zurückgestellt. Einen reibungsfreien Verklicker habe ich zwar gebaut, aber die Kreuz gegen den Wind macht Schwierigkeiten.

Gast #7385046
Lesenswert?

Ich habe das Gefühl, dass du zu viel mit Interrupts umsetzen willst.

Man kann Eingänge auch nacheinander abfragen. Multitasking kann man mit mehreren parallel ablaufenden Zustandsautomaten erreichen.

Interrupts benutzt man typischerweise nur dort, wo es unbedingt notwendig ist, die laufende Arbeit sofort zu unterbrechen um auf das Ereignis schnellstmöglich (binnen weniger Millisekunden oder noch schneller) zu reagieren.

Zum Beispiel nutzt man eine ISR, um seriell empfangene Bytes in einen Puffer zu übertragen. Schließlich wartet der Sender der Daten nicht den Moment ab, wo du empfangsbereit ist. Die Verarbeitung der Daten sollte aber nicht in der ISR stattfinden.

Einen Schaltkontakt sollte man aber normalerweise nicht an eine ISR koppeln, sondern aktiv abfragen.

Mit zu vielen Interrupts verzettelt man sich ganz schnell. Bedenke, dass dein AVR sowieso nur eine ISR gleichzeitig ausführen kann. Alle anderen Interrupts müssen eh warten, bis er wieder ins Hauptprogramm zurückgekehrt ist. Durch viele Interrupts wird die Abarbeitung von Ereignissen unter Umständen sogar langsamer, als eine sequentielle Abfrage der Eingänge im Hauptprogramm.

Wenn man mal bedenkt, dass kein Motor so schnell anlaufen und stoppen kann, frage ich mich, was das in deiner Anwendung wohl sein mag. Empfangene Kommandos in einen Puffer eintragen wäre ein Fall. Und sonst? Wofür brauchst du Interrupts?

#7385049
Lesenswert?

Reiner D. schrieb:

Weit gefehlt ! Der AVR ist sogar eigentlich zu klein, mir gehen sowohl die externen Interrupts (deshalb die PCINT) als auch die Timer aus, ich muß sogar Timer multiplexen...

Dann ist was falsch an Deinem Konzept.

Den Empfänger hast Du bestimmt über SBus, IBus oder Hott angeschlossen, das ist eine serielle Schnittstelle -> UART

Das hast Du ggf. Telemetrie über SPort, IBus oder Hott-Sensor, ebenfalls seriell -> der 2. UART

Dann liest Du GPS -> der 3. Uart

Dann produzierst Du PWM für die Servos -> 1 Timer (bis zu 16 Servos)

Was brauchst Du noch?

OP #7385060
Lesenswert?

//Timer 0 : PPM-Generator (für Servos und RC-Winden) //Timer 1 : 10HZ-Generator für NPRM-Scheduler //Timer 2 : PWM-Generator (CompA für Maschine ) //Timer 3 : PPM-Decoder (vom RC-Sender) //Timer 4 : PWM für Fall-Winden in Gruppen //Timer 5 : Entprellung der Inkrementgeber //UART0 : USB zum PC //UART1 : GPS

Klar könnte ich z.b. die Motorsteuerung mit nem Brushless und einem Stellerl machen, oder ein "Fahrtregler" für den DC-Motor. Aber warum kaufen, wenn das auch mit Software geht. Mein Empfänger kann nicht seriell, also Auswertung des PPM-Summensignals. Die Winden brauchen Inkrementgeber, weil ich die Wege und die Geschwindigkeit steuern will, also Interrupts. Die Inkrementgeber "prellen" beim 1/0-Übergang, wohl optische Gründe, könnte man auch filtern, aber SW ist lustiger. Und für Regler und digitale Filter brauche ich harte Echtzeit, also der Scheduler.

Gast #7385065
Lesenswert?

Ich steuere dir mit einem einzigen 8 Bit Timer 10 Servos an. Jemandem, der in Software nicht nicht so fit ist, würde ein PC9685 Modul empfehlen.

Timer 1 : 10HZ-Generator für NPRM-Scheduler Timer 5 : Entprellung der Inkrementgeber

Ich würde wie bei Arduino einen millis() Timer und alle andere Zeiten per Software davon ableiten.

Gast #7385067
Lesenswert?

Reiner D. schrieb:

Ein Katamaran, der geregelt auf einer Kufe fährt Eine Modellrakete, die wie ein Cruise-missile fliegt

Werde nicht albern, lerne erst mal programmieren.

Hast du eigentlich einen Debugger? Wenn nicht, dann ist jetzt vielleicht noch eine gute Gelegenheit, den ATmega 2560 (?) durch ein STM32 Nucleo Board zu ersetzen, da hast du den Debugger direkt mit drauf.

#7385073
Lesenswert?

Ja, also das wird sicher mit AVR machbar sein. Aber ich würde mir das in diesem Fall heute auch nicht mehr mit AVR antun, wenn es nicht unbedingt sein muss. Da würde ich eher einen billigen 32-Bit Mikrocontroller wie z.B. den ESP32 nehmen. Die maximal paar Milliwatt Mehrverbrauch fallen hier gar nicht ins Gewicht. Den kann man dann auch in Python programmieren, wenn man das möchte. Oder halt auch in vielen compilierten Sprachen wie C, C++ und Rust.

AVR nutze ich eigentlich nur noch da, wo es auf absolut geringen Energieverbrauch ankommt, oder wo die Anwendung trivial ist.

Außerdem würde ich unabhängig vom Controller so wenig Hardwaretimer wie möglich einsetzen. Ein simples Realtime-Scheduling mit festen Zeitscheiben ist viel einfacher und IMO auch robuster als etliche Interrupts, die sich ständig unterbrechen können. Das Scheduling kann von einem HW-Timer ableiten.

Die restlichen HW-Timer dann für z.B. PWM, was autonom in HW generiert wird.

Außerdem würde ich die Aktivitäten in den verbliebenen Interrupt Service Routinen auf das absolute Minimum beschränken.

Einfacher ist besser.

OP #7385087
Lesenswert?

Stefan F. schrieb:

Ich steuere dir mit einem einzigen 8 Bit Timer 10 Servos an.

Ja, ich auch. Brauche aber nicht so viele ;-)

ISR(TIMER0_COMPA_vect) { TCCR0B = 0; //zähler aus PORTA = PORTA & 248; //alle Pins auf 0 servo = servo + 1; if (servo > 4) { servo = 1; } //-------------------------------------- if (servo == 1) { PORTA |= 1; //Pin 22, Port A0 -> Ruder ist servo 1 OCR0A = Matrose.ruderwinkelsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16us) } if (servo == 2) { PORTA |= 2; //Pin 23, Port A1 -> Gaffel ist servo 2 OCR0A = Matrose.gaffelschotsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16 us) } if (servo == 3) { PORTA |= 4; //Pin 24, Port A2 -> Fock ist servo 3 OCR0A = Matrose.fockschotsollwert; TCCR0B = 4; //timer zählt los mit prescaler 256 (16 us) } //----------------------------------------- if (servo == 4) { OCR0A = 255; //Maximalwert, rund 13 ms Pause TCCR0B = 5; //timer zählt los mit prescaler 1024 (80us) } }

OP #7385097
Lesenswert?

Bei all diesen Projekten ist der uC nicht das Problem, oder ob das schönes C wird, sondern eher die Regelungstechnik (und bei der Rakete vielleicht die Servogeschwindigkeit). Versuche sind schon gelaufen.

Andere Beispiele für echt harte Regelprojekte : Quadrocopter oder self-balancing (siehe segway).

Beitrag #7385223 wurde von einem Moderator gelöscht.
#7385225
Lesenswert?

Hans-Georg L. schrieb:

Überschrift war OO mit C++

Bitte entschuldige, was möchtest Du uns damit sagen?

Wahrscheinlich wird dieses Kapitän-Matrosen Pattern in die Software Geschichte eingehen .... ;-)

Ja, vermutlich, vor allem, wenn es jemand in C++ sauber implementiert und seine Lösung hier zeigt (ich persönlich würde ja auf Wimalopaan tippen).

Nun, ich hab's mal in Python gebastelt, nur so aus Spaß, und natürlich ist das ein totaler Pipifax. Trotzdem: HF und YMMV.

PS: Sorry für das off-topic, lieber TO. Viel Glück und Erfolg bei Deinem spannenden und interessanten Segelprojekt! ;-)

PPS: Verdammt, jetzt aber... ;-)

Angehängte Dateien:
#7385240
Lesenswert?

Reiner D. schrieb:

//Timer 0 : PPM-Generator (für Servos und RC-Winden) //Timer 1 : 10HZ-Generator für NPRM-Scheduler //Timer 2 : PWM-Generator (CompA für Maschine ) //Timer 3 : PPM-Decoder (vom RC-Sender) //Timer 4 : PWM für Fall-Winden in Gruppen //Timer 5 : Entprellung der Inkrementgeber //UART0 : USB zum PC //UART1 : GPS

Timer5 brauchst Du nicht bzw. kannst das mit Deinem Timer1 zusammenfassen.

Und warum brauchst Du so viele externe PinChange-Interrupts?

OP #7385297
Lesenswert?

Sheeva P. schrieb:

Nun, ich hab's mal in Python gebastelt

@sheeva :

Find ich extrem spannend. Ich hab die letzten Jahre viel mir Python gespielt, natürlich nicht auf deinem Niveau, und rumgesucht, ob das auch auf dem AVR möglich ist. Ich hab leider nix vernünftiges gefunden. Wenn du erlaubst, stelle ich dir dazu später ein paar Fragen. Soll ich da ein extra topic machen, oder wie geht das ?

OP #7385307
Lesenswert?

Wilhelm M. schrieb:

brauchst Du so viele externe PinChange-Interrupts?

Ich hab aktuell 5 Winden, es sind aber noch drei Segel ausstehend (nochmal Winden) jede Winde einen Inkrementgeber, weil ich nicht bloß ein/aus steuern möchte.

Die normalen externen Interrupts sind schon überwiegend belegt an den Ports, und umlöten tun ich da nix mehr (du kannst dir vermutlich vorstellen, wie die Platine von hinten aussieht, wenn ein 65-jähriger mit Zitterfingern so einen Haufen Zeug mit Draht frei verlötet ;-).

Angehängte Dateien:
OP #7385318
Lesenswert?

Wilhelm M. schrieb:

Timer5 brauchst Du nicht bzw. kannst das mit Deinem Timer1 zusammenfassen.

Das Problem liegt andersrum.

Ich habe da einen Fehler im System : die Inkrementgeber "prellen", wahrscheinlich springt die Optik kurz nach der Kante ein paarmal hin-und her. Wenn ich nur einen Timer dafür benutze (klassische bounce-Lösung mit Totzeit), kann nur eine Winde zu einer Zeit laufen : sehr unsportlich ! Ich bräuchte im Kern sehr viele Timer um parallel setzen/bergen/reffen zu können, einen pro aktiver Winde.

Grübel. Hardwarelösung, also rummessen, analogen Filter entwerfen, oder einen Coprozessor (AtMegas hab ich genug). Weiß nicht. uP ist lustiger.

#7385326
Lesenswert?

Vielleicht nochmal grundsätzlich: der Titel ist "C++ Objektorientierung". Dir sollte bewusst sein, dass C++ keine rein objektorientierte Programmiersprache ist. Sondern C++ ist eine Sprache, mit der man auch(!) objektorientiert programmieren kann. Aber auch anders: imperativ-prozedural, funktional, generisch, meta-programmatisch, ...

Und der Code, den Du vorgestellt hast, ist mitnichten OOP. Denn die Grundprinzipien von OOP sind Kapselung in Klassen, Vererbung, Polymorphie und spätes Binden. Von diesen Prinzipien hast Du nichts umgesetzt.

Außerdem ist Deine Anwendung wohl so, dass Du auch nicht direkt OOP benötigst, da so ziemlich alles statisch.

Aber auch ist Dein Ansatz noch nicht einmal konsequent objektbasiert.

Zudem hast Du auch Klassen die etwas der internen Peripherie modellieren sollen. Hier ist es konzeptionell falsch, Instanzen von Klassen zu erzeugen, es sei denn, Du verwendest ein Muster zur Kapselung von globalen Zuständen in multiplen Instanzen wie etwas das Monostate-Pattern.

Also alles in allem: so wie Du das anfängst, hast Du keinerlei Vorteile gegenüber rein imperativ-prozeduraler Vorgehensweise. Und OOP lernt man nicht mit µC, sondern ganz normal auch dem PC. Aber da wiederhole ich mich.

OP #7385332
Lesenswert?

Wilhelm M. schrieb:

Hier ist es konzeptionell falsch, Instanzen von Klassen zu erzeugen,

Wieso ? Daß es zum Modell nicht passt ist eine Sache, aber warum darf eine funktionierende Programmiertechnik quasi "grundsätzlich" nicht für dies oder das benutzt werden ?

Ähnlich Frage : (Ich weiß, ist sakrosankt) Wieso immer Kapselung ? Ich verstehe die Vorteile in entsprechendem Kontext. Aber in so einem kleinen Projektchen, das nicht im Team entwickelt wird ? so what ? alles public und fertig ...

Laß mich ein Beispiel geben : wenn ich am Holm eines großen Segelflugzeuges klebe, nehme ich das beste Epoxi und mache vorher einen Klebekurs. Bei Spielzeug klebe ich mit Uhu, fertig.

#7385336
Lesenswert?

Reiner D. schrieb:

Wieso ? Daß es zum Modell nicht passt ist eine Sache, aber warum darf eine funktionierende Programmiertechnik quasi "grundsätzlich" nicht für dies oder das benutzt werden ?

Stellt Dir vor, Du erzeugst an unterschiedlichen Stellen in Deinem Code mehrere Instanzen der Klasse "scheduler" oder "i2c". Was erwartest Du, was dann passiert?

Ich habe nicht gesagt "grundsätzlich" falsch, sondern konzeptionell falsch.

OP #7385343
Lesenswert?

Das ist jetzt Nachhilfe pur, und ich danke dir dafür !

Ich schätze mal, mehrere Instanzen von I2C werden rein softwaremäßig funktionieren.( Wobei ich das Problem, das bei mehrmaligem include einer .h passiert, und mit "Include Guards" gelöst wird, noch nicht so genau verstanden habe)

Wenn dann aber die verschiedenen Objekte auf die nur einmal vorhandene Hardware zugreifen, knirscht es aber. Es mag mulitinstanzfähige Lösungen geben, die auf dem AVR ist es sicher nicht.

So war es aber auch nie gedacht, es ging damals nur um die Funktionsfähigkeit des Syntax-Gebäudes "Klasse-Objekt-Attribut usw...".

Und, auch akzeptiert : das muß raus aus dem Schifferl ;-)

#7385350
Lesenswert?

Reiner D. schrieb:

Ich schätze mal, mehrere Instanzen von I2C werden rein softwaremäßig funktionieren.( Wobei ich das Problem, das bei mehrmaligem include einer .h passiert, und mit "Include Guards" gelöst wird, noch nicht so genau verstanden habe)

Hier verwechselst Du "nicht compilieren" mit "zur Laufzeit was Falsches machen".

Das Thema "include guard" ist ein simples Thema der Strukturierung des Codes innerhalb der Übersetzungseinheiten. Hier hast Du in C++ alle Freiheiten, Hauptsache Du machst es richtig. Trotzdem gibt es ein übliches Verfahren, etwa die Klassendefinition und Definition der Elementfunktionen in Header und Implementierungsdatei zu unterteilen. Zusammen mit include-guards hilft dies zuverlässig, die ODR einzuhalten und Mehrfachdefinitionen innerhalb einer Übersetzungseinheit auszuschließen.

Das hat aber nicht mit dem Laufzeitproblem zu tun, was ich angesprochen habe.

Mehrere Exemplare des Typ i2c werden natürlich irgendwie "funktionieren", aber nicht das tun, was Du willst. Das ist dann ein semantisches Problem. Und ja, Du hast es erkannt: Objekte, die nicht ihren eigenen Zustand, sondern einen globalen Zustand (der, der internen Peripherie) modellieren sollen, benötigen besonderes Augenmerk. Eine Lösung ist das Monostate-Pattern. Eine andere ist es, eine Klasse nur mit static Elementen zu schreiben und es zu verbieten, Objekte davon zu erzeugen.

#7385352
Lesenswert?

Sheeva P. schrieb:

Hans-Georg L. schrieb:

Überschrift war OO mit C++

Bitte entschuldige, was möchtest Du uns damit sagen?

Das die Überschrift mit dem Thread nichts mehr zu tun hat.

Ja, vermutlich, vor allem, wenn es jemand in C++ sauber implementiert und seine Lösung hier zeigt (ich persönlich würde ja auf Wimalopaan tippen).

Auch dann wird es kein OO und kein C++ sein ;-)

Das Thema selbst ist sehr interessant und ich wünsche viel Erfolg !

(Firma: Gast) #7385358
Lesenswert?

Reiner D. schrieb:

Laß mich ein Beispiel geben : wenn ich am Holm eines großen Segelflugzeuges klebe, nehme ich das beste Epoxi und mache vorher einen Klebekurs. Bei Spielzeug klebe ich mit Uhu, fertig.

Ob Hobbybastler oder Profi.... Beide wollen am Ende eine funktionierende/stabile Software. So verwenden auch beide die gleichen Techniken. Manches mal sind die Hobby Leute gar noch verbissener.

Reiner D. schrieb:

alles public und fertig ...

Herrlich!

Natürlich kann man mit einer Tasse einen Nagel in die Wand hauen. Es zumindest versuchen. Oder bei einem Auto 3 Türen zuschweißen.

Einer der gewichtigsten Gründe für OOP ist eben die Kapselung. Die hoffentlich damit einhergehende leichte Wiederverwend-, Test- und Wartbarkeit.

Natürlich darfst du das in den Wind schlagen.

#7385364
Lesenswert?

Reiner D. schrieb:

Wilhelm M. schrieb:

Mit AVR hat das nichts zu tun:

Im Sinne der Nachhilfe nachgefragt :

Ich kenne aus der Industriewelt multiinstanzfähige HW, die also mehrere "gleichzeitige" Requests auffangen und geordnet abarbeiten kann. Hätte der I2C-Teil im AVR diese Fähigkeit, wären die parallelen Instanzen wohl möglich, oder ?

Die hast Du ja auch bei AVR: es gibt mehrere HW-Instanzen eines UART ;-)

Jetzt benötigst Du idealerweise eine Lösung, die es Dir erlaubt, passend zu den 3 HW-Uarts auch drei unterschiedliche Instanzen zu erzeugen: Instanz 1 bezieht sich auf Uart 1, Instanz 2 bezieht sich auch Uart 2, u.s.w., Instanz 42 bezieht sich auf ... was? Und idealerweise sollte dies Problem nicht erst zur Laufzeit auftauchen, sondern zur Compilezeit.

In C++ gibt es noch eine Art von "Instanz", und zwar wenn man aus einem Template eine Klasse erzeugt spricht man auch von Instanziieren eines Templates. Denn instanziieren bedeutet nur, aus etwas Abstraktem etwas Konkretes zu erzeugen: aus einer Klasse ein Objekt, oder aus einem Template eine Klasse. Der Template-Instanziierungsprozess läuft zur Compilezeit, und deswegen kann man hier dann die obige Prüfung einbauen, damit eine fehlerhafte Parametrierung gar nicht erst compiliert. Laufzeitfehler zu suchen is hässlich ;-)

#7385368
Lesenswert?

Reiner D. schrieb:

Hätte der I2C-Teil im AVR diese Fähigkeit, wären die parallelen Instanzen wohl möglich, oder ?

Auch mit nur einem Hardware-I2C steht dir frei, weitere (Software-Simulierte) I²C-Busse zu instanziieren, bei Arduino: "class SoftWire".

Und bei AVRs mit mehreren UARTs ist es auch üblich, dass da mehrere Serial-Objekte (+ ggfs. SoftSerial) instanziiert sind.

#7385374
Lesenswert?

Reiner D. schrieb:

Arduino F. schrieb:

Mehrere I2C Ports, dann auch mehrere z.B. Wire Instanzen.

nochmal nachgefragt : Ich kann z.B auf dem AtMega256 aus zwei Instanzen "gleichzeitig" (also innerhalb des Befehlszyklus) auf die I2C-Schnittstelle zugreifen (also z.b. zwei verschiedene Peripheriegeräte abfragen) ??

I2C ist "single master / multiple client".

Also Dein AVR kann viele Clients abfragen.

OP #7385376
Lesenswert?

M. K. schrieb:

Wenn du alles public machst ist es nur eine Frage der Zeit bis dein Schoner auf Grund läuft.

Danke für das schöne Bild ;-) Ich weiß, ich kämpfe gegen Windmühlen, trotzdem :

Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. Was hat ein setter dann für einen Sinn ?

Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch das nicht in meinem Spielzeugkontext.

Trotzdem bin ich brennend an diesen Aussagen interessiert, weil mir ja gerade der professionelle Blick auf das Thema fehlt !

#7385379
Lesenswert?

Reiner D. schrieb:

M. K. schrieb:

Wenn du alles public machst ist es nur eine Frage der Zeit bis dein Schoner auf Grund läuft.

Danke für das schöne Bild ;-) Ich weiß, ich kämpfe gegen Windmühlen, trotzdem :

Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. Was hat ein setter dann für einen Sinn ?

In C++ sagt man auch nicht unbedingt getter/setter. Die Unterscheidung kann hier der Compiler anhand des const-Attributes machen.

"Setter" haben die Aufgabe, nicht vorgesehene Objektzustände in Form von Zusicherungen auszuschließen und ggf. Abbildungen zwischen extern sichtbarem und intern modelliertem Zustand zu machen.

Stell Dir vor eine Klasse Point, die intern die Koordinaten in Polarkoordinaten modelliert, jedoch nach außer auch Cartesische Koordinaten anbietet.

Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch das nicht in meinem Spielzeugkontext.

Dur wirst Dich freuen, wenn Du nach 2 Wochen Pause Deinen eigenen Code wieder anschaust.

#7385393
Lesenswert?

Reiner D. schrieb:

Ich brauche keine getter/setter, wenn ich eh keine Fehlerprüfung mache. Was hat ein setter dann für einen Sinn ?

Wiederverwendbarkeit und sowas ist gut für Profi-Projekte, ich brauch das nicht in meinem Spielzeugkontext.

Es geht ja weder darum, dass man so etwas zwingend braucht oder ob etwas ein "Profiprojekt" ist. Natürlich kann man ohne auskommen. Aber insgesamt lebt es sich mit einer sauberen Datenkapselung (getter/setter) deutlich einfacher, je größer das Projekt wird. Die mentale Last wird sehr reduziert, wenn du dir nicht ständig Gedanken darüber machen musst, wer denn jetzt wieder von wo direkt auf irgendeine Variable zugreifen könnte. Was heute eine einfache Variable ist, kann morgen komplexer sein. Und mit einer sauberen Kapselung sind solche Anpassungen meist Klasseninterna.

Außerdem finde ich es lustig, wie zwischen Hobby- und Profiprojekt unterscheidest. :) Ich kann dir versichern, dass so manches Profiprojekt aussieht, als wäre es von Amateuren zusammengestümpert worden. Wenn ich eins gelernt habe, dann: Überall wird gefrickelt. Nirgendwo wird alles perfekt oder nach der "reinen Lehre" gemacht. Und am Ende funktioniert es dann meistens doch irgendwie zuverlässig. Man kann sich aber sehr sehr viel Arbeit sparen, wenn man einige Dinge von vorne herein richtig macht. Und da gehört eine vernünftige Datenkapselung IMO mit an die erste Stelle.

Beitrag #7385405 wurde von einem Moderator gelöscht.
OP #7385406
Lesenswert?

Nochmal : ok, ihr habt mit den meisten Aussagen wohl recht Nochmal : danke !

Verzeiht provozierende Rückfragen, ich versuche nur, den Kern der jeweiligen Thematik freizulegen.

Wie ist das allgemein hier ? Technisches Forum mit möglichst knapper, präziser Info, oder ist auch Geplauder erlaubt ? Wenn nicht erwünscht, sollten wir das Kaffeekränzchen stoppen, ansonsten macht's Spaß.

#7385411
Lesenswert?

Geplauder (Abschweifungen und ähnliches) gehört IMHO immer dazu wenn man tiefer ins Thema einsteigt und sich auch prima austauscht so wie das hier im Thread grade der Fall ist. Wichtig ist eigentlich nur, dass man auch den Bogen zum Threadthema wieder zurück findet.

OP #7385417
Lesenswert?

Hans-Georg L. schrieb:

Du könntest dir auch das Leben leichter machen und Platinchen (Matrosen) bauen. Ein kleiner MC und die Motortreiber darauf. Das würde dein Softwareproblem und den Kabelverhau reduzieren und skalierbar sein.

Da hast du mit Sicherheit recht. Wär ja auch spaßig, jede relevante Arbeit von nem kleinen Nano oder sowas machen lassen, quasi "Hardwareobjekte", und das über ein Bussystem zu vernetzen.

(Sowas hatte ich schon mal : ein Raspi mit Python hat kommuniziert (OPCuA)und gerechnet, ein Ardu seriell dran hat eine Delta-HW gesteuert.

Aber Hardware ist aktuell nicht mein Ding, ich tippe grad lieber und gehe auf die Reise durch die neue Welt der Objektorientierung. Den Python-Gedanken hat keiner aufgegriffen : AVR und Python, geht das ?

OP #7385457
Lesenswert?

In meinem Alter nehme ich mir das Recht auf "ästhetische Rechtschreibung". Und dazu zählt das, was du "Plenken" nennst.

Mal ehrlich, schaut das gut aus :

Beispiel: das ist nicht geplenkt!

Ist doch geplenkt viel schöner :

Beispiel : das ist geplenkt !

Ich hab doch Platz, wieso sollte ich das schöne Satzzeichen da dranquetschen ?

(Und wieder : beim Komma passt das finde ich, beim Fragezeichen nicht !!)

Ich hab hier eh schon nachgegeben, und verwende Großbuchstaben. Einer hat geschrieben, er kann das nicht lesen ...

Aber jetzt gleiten wir echt krass vom Thema ab ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren