Hi Ich bin jetzt zwangsbeglückt worden und muss C++ lernen.Ansich sollte es ja nicht so schwer sein, jedoch habe ich die Struktur bzw den Aufbau dahinter noch nicht so ganz verstanden. Was das Programm machen soll: Es soll eine Zahlenfolge über die Konsole einlesen und danach mit den Werte dann einmal integrieren und differenzieren (auf eine ganz panale art und weise). In C wär das ganze für mich überhaupt kein Problem. Jedoch muss ich es mit C++ machen und das ganze eben Objektorientiert. Ich habe mir jetzt auch das Skript noch einmal zu gemüte geführt. Jedoch jedesmal wenn ich glaube, es verstanden zu haben, erkenne ich im nächsten Schritt,dass ich es nicht verstanden habe. Nun wollte ich euch fragen, ob ihr mich etwas aufklären wie der Zusammenhang von Klasse, Funktion usw ist. Also Konkret wie das ganze in meinem Fall aussehen würde. Also wie ich die einzelnen Funktionen zu Berechnung schreibe, ist mir kein Rätsel. Was mir nur etwas schleierhaft ist, wie Funktionen und Klassen interagieren und wie ich nun von einem Eingegebnen Wert in die Klasse komme und von dort in die Funktion. Weiters verstehe ich den Zugriff auf eine Klasse nicht so ganz. Ich hoffe ihr könnt mir etwas weiterhelfen. mfg Schoasch
hm, alos erst mal macht OO nur dann richtig sinn wenn du etwas programmieren sollst/willst was einen bestimmten realitätsausschnitt bzw "reales" system darstellt zum beispiel eine alarmanlage oder eine heizung welches aus gegenständen/dingen (objekten) besteht die zusammen agieren um irgendeine systemleistung zu erbringen. Nur einen Algorithmus kann man nicht wirklich objektorientiert abbilden das ist quark mit soße. das was du dann tun musst ist das reale system so zu strukturieren wie es in der realiät auch aufgebaut ist aus objekten welche über eigenschaften (attribute) und verhalten verfügen (methoden) ... hast du eine textuelle beschreibung der aufgabe? cu BT
Hi Die Sinnhaftigkeit dieser Aufgabe sei einmal in den Raum gestellt. Aber irgendwie müssen wir auch einmal mit OO anfagen. Hier ist die Angabe: http://courses.mbi.tugraz.at/EINF-WS2006-2007/EINFUebung01.pdf Ich bin jetzt immerhin schon so weit, dass ich von einer Funktion, die in einer Klasse ist, einen Returnwert bekomme. Hast du einen Tipp für mich, wie ich am besten eine Variable initialisiere, damit sie drotzdem privat ist und nur beim 1. Mal mit 0 initialisiert ist? mfg Schoasch
Hallo, habe hier ein Buch gefunden welches zum Verständniss der OO vielleicht weiterhilft. http://www.galileocomputing.de/openbook/oo/index.htm Die Variable musst du als privat deklarieren und im Konstruktor der Klasse mit 0 initialisieren. Wie die Syntax in C++ ist kann ich dir leider nicht verraten. gruss ralf
Danke für den Link. Ich werde in mir das durchlesen. >Die Variable musst du als privat deklarieren und im Konstruktor der >Klasse mit 0 initialisieren. Jetzt wärs halt noch interessant wie man darauf zugreifen kann ;-) Aber irgendwie meckert der Compiler immer, wenn ich einen Konstruktor und Destruktor machen will.
1 | var = 0; |
Das geht natürlich nur in Methoden Deiner Klasse.
So. Schön langsam wirds. Mein Fehler war, dass ich nur den Konstruktor erstellt habe und den destruktor nicht gemacht habe.
Alle Variablen, die du innerhalb einer Klasse definierst, sind Member dieser Klasse. Die Attributierung public, private, protected regelt lediglich, wie von ausserhalb auf diese Member- variablen zugegriffen werden kann.
1 | //**************************************************************
|
2 | // Die Klassendefinition. Kommt normalerweise in ein Headerfile
|
3 | |
4 | class A |
5 | {
|
6 | public:
|
7 | A(); // diese Klasse hat einen Konstruktor |
8 | ~A(); // diese Klasse hat auch einen Destruktor |
9 | |
10 | int foo(); // und in dieser Klasse gibt es eine Funktion |
11 | // namens foo. Von C her kennst du das schon:
|
12 | // das ist ein ganz normaler Funktionsprototyp
|
13 | |
14 | private: // in dieser Klasse gibt es auch Dinge, die von aussen |
15 | // nicht sichtbar sein sollen. Die quasi einem Objekt
|
16 | // vom Typ A ganz alleine gehören und die niemanden
|
17 | // sonst was angehen
|
18 | |
19 | int m_Var; // zb. diese Variable hier |
20 | };
|
21 | |
22 | //****************************************************************
|
23 | // und hier die Implementierung der oben definierten Klasse
|
24 | // die Implementierung findet sich normalerweise in einem
|
25 | // eigenen *.cpp File
|
26 | |
27 | // zunächst der Konstruktor
|
28 | A::A() |
29 | {
|
30 | // Aufgabe des Konstruktors ist es, ein Objekt dieser
|
31 | // Klasse in einen definierten Zustand zu bringen.
|
32 | // Für uns mag das zb. bedeuten, dass die Klassenvariable
|
33 | // m_Var den Wert 5 haben soll.
|
34 | |
35 | m_Var = 5; |
36 | |
37 | // sobald also ein Objekt vom Typ A 'zur Welt kommt', wird der
|
38 | // Konstruktor aufgerufen und dieser setzt die Variable m__Var
|
39 | // auf 5
|
40 | }
|
41 | |
42 | // Hier ist der Destruktor
|
43 | // er wird aufgerufen, wenn ein Objekt 'stirbt'
|
44 | // Hier haben wir nichts zu tun und eigentlich sollte man
|
45 | // dann keinen Destruktor vereinbaren, aber was solls:
|
46 | A::~A() |
47 | {
|
48 | }
|
49 | |
50 | // und jetzt die Funktion foo
|
51 | // da foo ja Mitglied der Klasse ist, hat sie selbstverständlich
|
52 | // auf alle Funktionen und Variablen innerhalb dieser Klasse Zugriff
|
53 | int A::foo() |
54 | {
|
55 | return m_Var; |
56 | }
|
57 | |
58 | |
59 | //****************************************************
|
60 | // Jetzt muss diese Klasse nur noch verwendet werden
|
61 | |
62 | int main() |
63 | {
|
64 | A DasObjekt; // Eine Variable namens 'DasObjekt' wird |
65 | // definiert. Es ist vom Typ A
|
66 | // Achtung: Da hier ein Objekt vom Typ A 'zur
|
67 | // Welt kommt', wird sofort nachdem der Speicher
|
68 | // dafür reserviert ist,der Konstruktor für das
|
69 | // Objekt aufgerufen. WIr wir wissen, setzt der
|
70 | // die Membervariable A::m_Var auf 5
|
71 | |
72 | // Das heist, hier an dieser Stelle, ist der
|
73 | // Konstruktor bereits durch und A::m_Var enthält
|
74 | // bereits einen vernünftigen Wert. Wir können nicht
|
75 | // darauf zugreifen, weil A::m_Var ja private
|
76 | // definiert ist (und das soll auch so sein)
|
77 | // aber, wenn wir die Funktion foo aufrufen, so
|
78 | // liefert die die 5 zurück
|
79 | |
80 | // rufe für das Objekt DasObjekt die Funktion
|
81 | // foo auf
|
82 | int j = DasObjekt.foo(); |
83 | |
84 | // j enthält jetzt den Wert den die Funktion DasObjekt.foo
|
85 | // zurückliefert. Das ist 5
|
86 | |
87 | A NochEinObjekt; // Noch ein Objekt vom Typ A wird definiert |
88 | // Auch für dieses Objekt wird jetzt in diesem
|
89 | // Moment der Konstruktor aufgerufen, welcher
|
90 | // NochEinObjekt::m_Var auf 5 setzt.
|
91 | |
92 | // Achtung: Beide Objekte, DasObjekt und
|
93 | // NochEinObjekt verfügen beide jeweils über
|
94 | // eine eigene Member-Variable m_Var. Die
|
95 | // eine hat mit der anderen nicht das geringste
|
96 | // zu tun.
|
97 | |
98 | } // Hier, mit der schliessenden Klammer, ist der Block zuende |
99 | // der den Lebensbereich der beiden A Objekte darstellt. D.h.
|
100 | // die beiden A Objekte sterben hier. Als Konsequenz daraus
|
101 | // wird für beide Objekte jeweils der Destruktor aufgerufen
|
> Die Sinnhaftigkeit dieser Aufgabe sei einmal in den Raum gestellt. Aber > irgendwie müssen wir auch einmal mit OO anfagen. Irgendwie schon, aber dazu wäre eine Aufgabe, bei der OO wenigstens in irgendeiner Weise sinnvoll wäre, wesentlich besser geeignet. > Hier ist die Angabe: > http://courses.mbi.tugraz.at/EINF-WS2006-2007/EINF... Ok. Viel mit OO ist da einfach nicht rauszuholen. Ich würde dafür eigentlich einfach nur vier Funktionen schreiben: - Werte einlesen - Differenzieren - Integrieren - Ausgeben Sowas einfach in eine Klasse zu schreiben, geht zwar, hat aber nichts mit OO zu tun. Man könnte im Prinzip zwei Klassen "Differenzierer" und "Integrierer" schreiben und diese von einer gemeinsame Basisklasse ableiten, aber das bringt's nicht. Dafür ist die Aufgabe einfach zu klein.
> Man könnte im Prinzip zwei Klassen "Differenzierer" und > "Integrierer" schreiben Ich denke so ist das auch gedacht: Eine Klasse Integrator, eine Klasse Differentiator, davon jeweils ein Objekt erzeugen und nacheinander Werte reinschaufeln. Beide Objekte (Integrator, Differentiator) sollen natürlich auch Auskunft über ihren jeweilgen Zustand (sprich den integrierten, bzw. differentierten Wert) geben können. Nimm als Motivation einfach ein Signal-Simulationsprogramm an. 2 Elemente in diesem Baukasten sind Integrator, Differentiator. Ein richtiges Simulationsprogramm müsste solche Objekte zur Laufzeit noch miteinander verbinden können, bzw. beliebig viele derartige Objekte erzeugen und verwalten können. Aber hey! Irgendwo muss jeder mal wo anfangen.
@Karl Heinz Buchegger: Besten dank für diese informative Erklärung. Das hat jetzt einiges an Ordnung in mein C++-Wissen gebracht. >Man könnte im Prinzip zwei Klassen "Differenzierer" und >"Integrierer" schreiben und diese von einer gemeinsame Basisklasse >ableiten, aber das bringt's nicht. Dafür ist die Aufgabe einfach zu >klein. Naja... Ich glaube wir sollte das eh mit Basisklasse und abgeleiteten Klassen machen, aber das kann ich noch nicht. Zuerst mach ich es einmal so. Ich finde das Beispiel auch ziemlich unpassend und vorallem uneffektiv. In C wäre das ganze Programm glaube ich nur halb so gross und auch viel übersichtlicher. Aber nunja... der Professor wills halt einmal so.
Lies dir auch mal folgendes durch: Beitrag "Re: Wie große Programme programmieren?" > In C wäre das ganze Programm glaube ich nur halb so gross und auch viel > übersichtlicher Auf lange Sicht gesehen nicht. OO ist einfach nur eine Technik die dir hilft, Struktur und damit Übersicht in ein Programm zu kriegen.
1 | int main() |
2 | {
|
3 | Integrator Integrierer; |
4 | Differentiator Differenzierer; |
5 | double Signal; |
6 | |
7 | while( std::cin >> Signal ) { |
8 | Integrierer.AddSample( Signal ); |
9 | Differenzierer.AddSample( Signal ); |
10 | |
11 | std::cout << "Differenzierer jetzt " << Differenzierer.Value() << "\n"; |
12 | std::cout << "Integrierer jetzt " << Integrierer.Value() << std::endl; |
13 | }
|
Dieses Hauptprogramm ist selbsterklärend. Da brauch ich keinen Kommentar oder sonstwas, das mir erklärt was hier eigentlich passiert. Ich kann auch super leicht ablesen, dass sowohl Integrator als auch Differentiator jeweils eine Methode AddSample bzw. Value unterstützen. Ich brauch nicht mit irgendwelchen dubiosen globalen Variablen jonglieren sondern alles ist dort wo es hingehört: Sowohl Integrator als auch Differntiator enthalten selbst alles was benötigt wird um jeweils neue Signalwerte zu verarbeiten. Das Hauptprogramm muss sich nicht darum kümmern. Alles was es tun muss ist, ein Objekt vom jeweiligen Typ anzulegen. Durch das Objekt, kriegt das Hauptprogramm die komplette Maschinerie die hinter dem Objekt steht, zur Verfügung gestellt.
Ich danke euch für eure Hilfe. Ich hab das Programm jetzt einmal funktionsfähig zusammengebracht. Jetzt ist nur mehr Kosmektik angesagt(Dialog mit Benutzer und Eingabefehlererkennung). Und ich glaube, dass ich es auch schön langsam kappiert habe wie das ganze so läuft. Jetzt bin ich recht optimistisch, dass ich mich nicht ganz plamieren werden bei der der Prüfung gggg mfg Schoasch
Ich habe euren Thread angeregt mitverfolgt und würde gerne wissen, wie das Ganze nun aber mit abgeleiteten-Klassen aussehen würde, eben eine Basis und differenzierer und integrierer als Ableitungen davon. Inwieweit würde hier virtual zur Anwendung kommen, würde es überhaupt sinn machen um hier Polymorphismus(ich denke das ist der richtige Ausdruck) anzuwenden? Wo liegen potentielle Tücken, auf was soll man achten?
Ob Inheritance und Polymorphie hier Sinn machen würde, hängt von der Anwendung ab, die ich schreibe. In der vorgegebenen Aufgabenstellung macht es keinen Sinn. Wenn ich aber eine andere Aufgabenstellung wähle, dann macht das sehr wohl Sinn (Kurzbeschreibung): Zu schreiben ist ein Simulationssystem, bei dem die Bausteine zur Laufzeit aus einem Vorrat ausgewählt werden und interaktiv miteinander vernüpft werden können. In diesem Fall wird es irgendwo einen Container geben, der alle in der konkreten Situation verbauten Bausteine halten muss. Das geht in C++ nur dadurch, dass man einen Container von Pointern hat. Und daraus folgt, dass sowohl Integrator als auch Differentiator von einer gemeinsamen Basisklasse, nennen wir sie mal Baustein, ableiten muss, damit der Container lauter Pointer auf Baustein halten kann. Da aber verarbeitende Funktionen aus dem Container wiederrum nur Pointer auf Bausteine bekommen, muss die eigentliche Funktionalität mittels polymorphem Verhalten angestossen werden. Jeder 'Baustein' hat eine Funktion Input, mit der man an den Eingang des Bausteins einen Wert anlegt und hat zb. eine Funktion Output, die den Signalwert am Ausgang wiedergibt. Die Anzeigeklasse, muss nun nicht wissen, welchen Baustein sie konkret bearbeitet: Sie lässt sich einfach vom Container einen Baustein-Pointer nach dem anderen geben, ruft polymorph über den Pointer die Output Funktion auf und schreibt den erhaltenen Wert zb. neben die graphische Abbildung. Konkret würde das zb. so aussehen:
1 | class Baustein |
2 | {
|
3 | public:
|
4 | virtual ~Baustein() {}; |
5 | |
6 | virtual const char* Type() { return "unbekannt"; } |
7 | virtual void Input( double Value ) = 0; |
8 | virtual double Output() = 0; |
9 | };
|
10 | |
11 | class Integrator: public Baustein |
12 | {
|
13 | public:
|
14 | Integrator() : m_Sum( 0.0 ) {} |
15 | |
16 | virtual const char* Type() { return "Integrator"; } |
17 | virtual void Input( double Value ) { m_Sum += Value; } |
18 | virtual double Output { return m_Sum; } |
19 | |
20 | private:
|
21 | double m_Sum; |
22 | };
|
23 | |
24 | class Differentiator : public Baustein |
25 | {
|
26 | public:
|
27 | Differentiator() : m_Last( 0.0 ), m_Diff( 0.0 ) {} |
28 | |
29 | virtual const char* Type() { return "Differentiator "; } |
30 | virtual void Input( double Value ) { m_Diff = Value - m_Last; |
31 | m_Last = Value; } |
32 | virtual double Output() { return m_Diff; } |
33 | |
34 | private:
|
35 | double m_Last; |
36 | double m_Diff; |
37 | };
|
38 | |
39 | int main() |
40 | {
|
41 | double Signal; |
42 | Baustein* Elems[2]; // Die 'Simulation' kann jetzt grade |
43 | // mal 2 Bausteine halten
|
44 | |
45 | Elems[0] = new Integrator; |
46 | Elems[1] = new Differentiator; |
47 | |
48 | while( std::cin >> Signal ) { |
49 | |
50 | for( int i = 0; i < 2; ++i ) { |
51 | Elems[i]->Input( Signal ); |
52 | std::cout << Elems[i]->Type() << " jetzt " |
53 | << Elems.Output() << std::endl; |
54 | }
|
55 | }
|
56 | |
57 | delete Elems[0]; |
58 | delete Elems[1]; |
59 | }
|
Man beachte, wie innerhalb der Schleife keinerlei Information mehr benötigt wird, von welchem Typ den nun das Objekt ist, mit dem gearbeitet wird. Wenn da jetzt ein zusätzlicher möglicher Baustein, sagen wir mal ein Inverter in das System eingearbeitet werden müsste, so ändert sich an der Schleife genau gar nichts: Die zusätzliche Inverter Klasse wird als Klasse geschrieben wird mit den notwendigen virtuellen Funktinen ausgestattet. Ok Irgendwann muss natürlich mal ein Objekt davon erzeugt werden, aber die Schleife, die die 'Simulation antreibt' ändert sich überhaupt nicht.
Hi Ist zwar schon ein bisschen her, aber jetzt muss ich mich wiedermal mit diesem Programm beschäftigen. Nur hab ich jetzt ein kleines Problem und ich kann es nicht so lösen wie ich glaube es zu Lösen können. Und zwar gehts jetzt darum, dass ich jetzt das programm so machen muss, dass man diverse "Bausteine" hintereinander schalten kann. Was mir nicht klar ist: Wie übergebe ich jetzt das Ergebnis auf das nächste Baustein? Ich hab jetzt einmal folgendes probiert:
1 | Tempvalue = Elems[i]->Output(); |
2 | Elems[i+1]->Input( Tempvalue ); |
Nach meinem Verständniss sollte in Tempvalue der Ausgabewert stehen. Und diesen übergebe ich dann in das nächste Element. (Tempvalue ist als double deklariert.) Aber wenn ich das programm Compiliere, kommt zwar kein fehler, aber nach der 1. Eingabe eines Wertes, beendet das Programm. Was hat es denn da? Was mache ich falsch? mfg Schoasch
Es könnte beispielsweise sein, daß i + 1 so groß oder gar größer wird wie die Anzahl der Elemente des Arrays Elems. Als Arrayindex darf aber nur ein Wert zwischen 0 und Anzahl-der-Elemente-Minus-1 verwendet werden. Daß Dein Programm sich beendet, wird daran liegen, daß durch den Arrayüberlauf irgendwo ins Nirvana gefasst wird. Mal drwtsn32* aufgerufen? Mal das Programm im Debugger laufengelassen? *) angenommen, daß Du Windows verwendest
Aja.. ok stimmt. Da war ich etwas übermütig mit meinen Array-Elementen. :-) Ok.. im Grunde würds ja funktionieren :-) Aber ich hab jetzt echt wo einen Wurm in meinen Array-Elementen drin, der mir gerade etwas zu kopfe steigt. Ich hab das ganze nemlich jetzt auf eine dynamische Erweiterung umgebaut. Und dadurch hat sich das ganze etwas verkomplziert. Was ist denn bitte : drwtsn32* ? Wie man dieser Frage wohl entnehmen kann, hab ich es nicht aufgerufen :-) Und debuggen funktioniert derweilen auch noch nicht ganz, da ich nicht weis wie das in diesem Compiler funktioniert. Also "debugge" ich mit der Konsole momentan 8-) mfg Schoasch
So Das ganze läuft jetzt. Es waren echt nur fehler mit dem Array. Jetzt hat das ganze auch noch einen Komperator verpasst bekommen. DAnke für Hinweise.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.