Ich finde die Videos sehr gut strukturiert, dieses Video und auch die vielen anderen erklären gut die jeweiligen Funktionsweisen und Zusammenhänge. Prima ist auch, dass die Programmtexte schon vorbereitet sind und man nicht auf lange Schreibaktionen warten muss. Alles ist einfach erklärt und wird meist am Ende des Videos zusammengefasst. Prima, danke, das hilft alles sehr!
Danke für die Blumen. Das Setup wollte ich eigentlich vor Ewigkeiten schonmal detailliert beschreiben, aber wie das so ist: Compiler ist ein GCC unter Linux (aktuell 4.7.3, aber das ändert sich, je nachdem, an welchem Rechner ich gerade arbeite). Der Editor ist Kate mit einem größer eingestellten Schriftschema. Die Konsole ist die KDE-Konsole ohne Rand und mit größer eingestellter Schrift. Bei Kate und Konsole sind die Fensterrahmen etc. außerhalb des Aufzeichnungsrahmens und daher unsichtbar.
Memberfunktionen, die als const gekennzeichnet sind, können auf const-Objekte aufgerufen werden. Will heißen: const Haustier tier; tier.gibLaut(); ist zulässig. Methoden, die nicht so gekennzeichnet sind, können nicht so aufgerufen werden. Das kommt vor allem dann zum Tragen, wenn Objekte als Parameter übergeben werden. Letzlich kennzeichnet eine const-Methode das Versprechen, das eigene Objekt nicht zu ändern. Das gibt dem Compiler gewisse Freiheiten bei der Optimierung, wenn er sich drauf verlassen kann, dass ein Methodenaufruf nichts ändert. Grundsätzlich gehe ich so an den Entwurf ran, dass ich Methoden grundsätzlich const mache, bis ich feststelle, dass ich das eigene Objekt ändern muss. Einfach so eine Methode zum defensiven Programmieren.
Zur Compilezeit steht doch schon fest, das "geraeusch" mit den erlaubten Unterobjekten aufgerufen werden darf und k ist ein Katze Objekt und da darf nur Methode mit "miau "aufgerufen werden. Erscheint mir nicht ganz plausibel "Bindung zur Laufzeit". Anders wäre es, wenn ich abhängig von einem errechneten Wert eine Methode aufrufe. Das würde wirklich zur Laufzeit passieren.
Ein guter Compiler, der funktionsübergreifend optimiert, kann hier im konkreten Beispiel tatsächlich über die Nachverfolgung der Variablenbindungen festellen, welche konkreten Implementierungen hier aufgerufen werden müssen. Spätestens wenn "geraeusch()" allerdings in einer Library ist und bereits vorkompiliert wurde, wird das etwas schwierig. Daher erfolgt das Binden tatsächlich dynamisch zur Laufzeit über den Mechanismus, den ich im nachfolgenden Videos beschreibe.
Damit wird das Objekt via Call-By-Reference übergeben. Ohne das & würdest du innerhalb dwer Funktion eine Kopie des Objekts erzeugen, was unnötig Speicher frisst.
Vielen Dank! Perfekte Erklärung, könnten Sie auch Erklärungsvideos zu Komposition und Aggregation machen? Ich schreibe in 2 Wochen meine Klausur und sie sie meine Hoffnung..
Komposition und Aggregation sind eigentlich eher Begriffe aus der Softwarearchitektur und nicht C++-spezifisch. Ich werde daher in dieser Serie zumindest kein Video darüber machen (und in den nächsten zwei Wochen wohl eher auch nicht). Die grundsätzliche Unterscheidung der beiden ist allerdings relativ einfach: kann ein Objekt ohne ein anderes bestehen (bspw. ein Mitarbeiterobjekt kann auch ohne Zuweisung zu einem Team in einem Modell existieren)? Dann ist es Aggregation (in C++ mit verschiedenen Möglichkeiten ausdrückbar. Ich würde wahrscheinlich einen std::shared_ptr bevorzugen). Kann das Objekt nicht ohne das umgebende existieren (bspw. ergibt der Name eines Teams ohne das Team-Objekt selbst keinen Sinn), dann ist es eine Komposition. Das würde ich dann immer als direktes Feld (by-value) oder im speziellen Sonderfällen als std::unique_ptr ausdrücken.
+DeathRipper88 Ich nehme mal an, dass du beim Abtippen die Funktion geraeusch() vergessen hast. Ich muss wirklich irgendwann mal die ganzen alten Folgen nachziehen, so dass man die Quelltexte runterladen kann. Für alle Folgen ab der 14. ist das jeweils im Begleittext möglich.
was ich aber hier nicht verstehe. Wie du gesagt hast, koennen wir auch in die main FKT k.gibLaut(); schreiben. Zur demonstration, hast du ja mit referenzen gearbeitet. Aber wenn wir es anders schreiben(also in die main mit k.gibLaut();), bringt mir das virtual doch nichts, oder? Bei der normalen vererbung kann ich doch in der abgeleiteten Klasse die vererbete FKT doch auch ganz normal überschreiben. Somit schreib ich in der main ja dann auch wieder: k.gibLaut(); ->Rufe katze objekt auf und benutze die FKT gibLaut. Also genau das gleiche wie bei virtual
Ich bin nicht sicher ob ich deine Frage richtig verstehe. Ja, man kann in der main k.gibLaut() aufrufen und es wird auch ohne virtual korrekt sein, aber nur weil k auch als Katze deklariert ist. Der Sinn von virtual Funktionen ist, dass man das Objekt als ein Objekt der Vaterklasse deklarieren kann und es dennoch auf die Funktion der eigentlichen Implementierung zugreift. Wenn du ohne virtual sowas wie Haustier *k = new Katze(); k->gibLaut(); schreibst, dann wird die Funktion der Haustier Klasse aufgerufen, nicht der Katze Klasse.
Ich finde die Videos sehr gut strukturiert, dieses Video und auch die vielen anderen erklären gut die jeweiligen Funktionsweisen und Zusammenhänge. Prima ist auch, dass die Programmtexte schon vorbereitet sind und man nicht auf lange Schreibaktionen warten muss. Alles ist einfach erklärt und wird meist am Ende des Videos zusammengefasst. Prima, danke, das hilft alles sehr!
Stark erklärt. Bestens gemacht
Gut erklärt. Danke!
ich bin total begeistert von deinen Videos.Kannst du uns sagen, welche Programme bzw. Compiler du für die Programmieren in Videos verwendest?
Danke für die Blumen.
Das Setup wollte ich eigentlich vor Ewigkeiten schonmal detailliert beschreiben, aber wie das so ist: Compiler ist ein GCC unter Linux (aktuell 4.7.3, aber das ändert sich, je nachdem, an welchem Rechner ich gerade arbeite). Der Editor ist Kate mit einem größer eingestellten Schriftschema. Die Konsole ist die KDE-Konsole ohne Rand und mit größer eingestellter Schrift. Bei Kate und Konsole sind die Fensterrahmen etc. außerhalb des Aufzeichnungsrahmens und daher unsichtbar.
Sehr gut erklärt und auch ein gutes Beispiel! Habe ich viel besser verstanden als in unserer Vorlesung, vielleicht solltest du Dozent werden ;-D
+memento Danke für die Blumen. Und zum Thema "Dozent": unter anderem arbeite ich als Dozent, wenn auch nicht für C++.
Danke für das lehrreiche Video : )
Wofür genau benötigt man das "const" nach den Funktionen?
Memberfunktionen, die als const gekennzeichnet sind, können auf const-Objekte aufgerufen werden. Will heißen:
const Haustier tier;
tier.gibLaut();
ist zulässig. Methoden, die nicht so gekennzeichnet sind, können nicht so aufgerufen werden. Das kommt vor allem dann zum Tragen, wenn Objekte als Parameter übergeben werden.
Letzlich kennzeichnet eine const-Methode das Versprechen, das eigene Objekt nicht zu ändern. Das gibt dem Compiler gewisse Freiheiten bei der Optimierung, wenn er sich drauf verlassen kann, dass ein Methodenaufruf nichts ändert. Grundsätzlich gehe ich so an den Entwurf ran, dass ich Methoden grundsätzlich const mache, bis ich feststelle, dass ich das eigene Objekt ändern muss. Einfach so eine Methode zum defensiven Programmieren.
Zur Compilezeit steht doch schon fest, das "geraeusch" mit den erlaubten Unterobjekten aufgerufen werden darf und
k ist ein Katze Objekt und da darf nur Methode mit "miau "aufgerufen werden. Erscheint mir nicht ganz plausibel "Bindung zur Laufzeit".
Anders wäre es, wenn ich abhängig von einem errechneten Wert eine Methode aufrufe. Das würde wirklich zur Laufzeit passieren.
Ein guter Compiler, der funktionsübergreifend optimiert, kann hier im konkreten Beispiel tatsächlich über die Nachverfolgung der Variablenbindungen festellen, welche konkreten Implementierungen hier aufgerufen werden müssen. Spätestens wenn "geraeusch()" allerdings in einer Library ist und bereits vorkompiliert wurde, wird das etwas schwierig. Daher erfolgt das Binden tatsächlich dynamisch zur Laufzeit über den Mechanismus, den ich im nachfolgenden Videos beschreibe.
dumme frage für was steht das &h bei den funktionen? Ist das eine Adresse und wenn von was???
Damit wird das Objekt via Call-By-Reference übergeben. Ohne das & würdest du innerhalb dwer Funktion eine Kopie des Objekts erzeugen, was unnötig Speicher frisst.
Vielen Dank! Perfekte Erklärung, könnten Sie auch Erklärungsvideos zu Komposition und Aggregation machen? Ich schreibe in 2 Wochen meine Klausur und sie sie meine Hoffnung..
Komposition und Aggregation sind eigentlich eher Begriffe aus der Softwarearchitektur und nicht C++-spezifisch. Ich werde daher in dieser Serie zumindest kein Video darüber machen (und in den nächsten zwei Wochen wohl eher auch nicht). Die grundsätzliche Unterscheidung der beiden ist allerdings relativ einfach: kann ein Objekt ohne ein anderes bestehen (bspw. ein Mitarbeiterobjekt kann auch ohne Zuweisung zu einem Team in einem Modell existieren)? Dann ist es Aggregation (in C++ mit verschiedenen Möglichkeiten ausdrückbar. Ich würde wahrscheinlich einen std::shared_ptr bevorzugen). Kann das Objekt nicht ohne das umgebende existieren (bspw. ergibt der Name eines Teams ohne das Team-Objekt selbst keinen Sinn), dann ist es eine Komposition. Das würde ich dann immer als direktes Feld (by-value) oder im speziellen Sonderfällen als std::unique_ptr ausdrücken.
Bei mir sagt er compiler fehler:
77 13 C:\Users\Patrick\Desktop\Theorie\Uebvirtuell.cpp [Error] 'geraeusch' was not declared in this scope
+DeathRipper88 Ich nehme mal an, dass du beim Abtippen die Funktion geraeusch() vergessen hast. Ich muss wirklich irgendwann mal die ganzen alten Folgen nachziehen, so dass man die Quelltexte runterladen kann. Für alle Folgen ab der 14. ist das jeweils im Begleittext möglich.
was ich aber hier nicht verstehe. Wie du gesagt hast, koennen wir auch in die main FKT
k.gibLaut();
schreiben.
Zur demonstration, hast du ja mit referenzen gearbeitet.
Aber wenn wir es anders schreiben(also in die main mit k.gibLaut();), bringt mir das virtual doch nichts, oder?
Bei der normalen vererbung kann ich doch in der abgeleiteten Klasse die vererbete FKT doch auch ganz normal überschreiben. Somit schreib ich in der main ja dann auch wieder:
k.gibLaut();
->Rufe katze objekt auf und benutze die FKT gibLaut.
Also genau das gleiche wie bei virtual
Ich bin nicht sicher ob ich deine Frage richtig verstehe.
Ja, man kann in der main k.gibLaut() aufrufen und es wird auch ohne virtual korrekt sein, aber nur weil k auch als Katze deklariert ist. Der Sinn von virtual Funktionen ist, dass man das Objekt als ein Objekt der Vaterklasse deklarieren kann und es dennoch auf die Funktion der eigentlichen Implementierung zugreift.
Wenn du ohne virtual sowas wie
Haustier *k = new Katze(); k->gibLaut();
schreibst, dann wird die Funktion der Haustier Klasse aufgerufen, nicht der Katze Klasse.