Performancemythen?
-
scrub schrieb:
Jetzt sag ich Dir mal, was ich zuallermeist gehört habe und was (nicht deshalb!) sich auch logisch anhört:
Objektorientiert ist, wenn man statt einem Haufen Daten und einem anderen Haufen Funktionen ganz klar bestimmten Daten(-typen) bestimmte Funktionen zuordnet, man also bereits im Quelltext genau sehen kann, daß miau() zur Katzenklasse und wau() zur Hundeklasse gehört- statt sich jedesmal selbst die passende Funktion rauszuschen, die man gerade braucht.Ich bemühe mich nicht "loszupampen"... :->
Für wau() und miau() braucht man kein OOP. Abstrahiert man das Problem, hat es allerdings Sinn eine abstrakte Form von wau() und miau() virtuell zu gestalten:
class Tier { public: virtual void GibLaut() { std::cout << "Hallo!"; } }; class Katze : public Tier { public: virtual void GibLaut() { std::cout << "Miau"; } }
Läßt Du das virtual weg, verzichtest Du auf OOP, dein Programm orientiert sich nicht am Objekt, sondern am Typ:
class Tier * tier = new Katze(); tier->GibLaut(); // Ignoriert, dass das Objekt eine Katze ist und gibt "Hallo" aus, weil Tiere sagen nunmal "Hallo".
Laut "eurer" Definition ist das Ignorieren des Objekts trotzdem objektorientiert. Das verstehe ich nicht und niemand erklärte es mir bisher.
scrub schrieb:
Die Begrifflichkeiten virtueller Funktionen und der restliche Krempel, dies alles kam in diesem Erklärungen des Themas OO _nie_ vor, kein einziges Mal. Ich lese davon in Deinen Beiträgen zum ersten Mal.
Hast Du Dir OOP speziell bezogen auf C++ angelesen und zwar in einem SEHR detailierten Buch, oder zum Beispiel an Java oder C# gelernt?
In Java benötigst Du 'virtual' nicht, weil Java viele Dinge implizit regelt. Du kannst Objekte nicht einbetten, weil Klassen grundsätzlich Referencetypes sind und Methoden sind grundsätzlich "virtual", solange Du sie nicht als "final" (also "nicht virtual" und damit in Java als nicht überschreibbar) erklärst. In C++ musst Du Objektorientierung explizit anfordern, während Du sie in Java oder C# implizit erhälst.
C++ nimmt die schnellste Methode, Java die flexiblere. Dafür zahlt Java allerdings auch nochmal in der Laufzeit, weil auch wirklich jede kleine Funktion über OOP dereferenziert werden muss.Wenn Du OOP aus allgemeinen Beschreibungen lernst oder eben mit Java gelernt hast, halte ich es nicht verwunderlich, dass in den Beschreibungen der Sonderfall C++ mit explizitem "virtual" nicht auftaucht.
OOP ist deswegen in Java nichts anderes als in C++. Die Sprachen sind ähnlich, aber eben nicht identisch: Man muss seine Wünsche etwas anders formulieren.
-
scrub schrieb:
Objektorientiert ist, wenn man statt einem Haufen Daten und einem anderen Haufen Funktionen ganz klar bestimmten Daten(-typen) bestimmte Funktionen zuordnet, man also bereits im Quelltext genau sehen kann, daß miau() zur Katzenklasse und wau() zur Hundeklasse gehört - statt sich jedesmal selbst die passende Funktion rauszuschen, die man gerade braucht.
Genau so habe ich Programmieren gelernt. Allerdings gab es zur der Zeit den Begriff "OOP" noch nicht. Seltsam. Aber egal.
-
Xin schrieb:
Für wau() und miau() braucht man kein OOP. Abstrahiert man das Problem, hat es allerdings Sinn eine abstrakte Form von wau() und miau() virtuell zu gestalten.
Bereits an dem Punkt scheiden sich beide Erklärungsvarianten: Gemäß den mir bekannten Definitionen ist es bereits objektorientiert, wenn ich eine Klasse "Katze" schreibe, der ich bestimmte Eigenschaften (Rasse, Geschlecht) und Funktionen (Fell abziehen, toasten) zuordne. Es ist hingegen nicht erforderlich, "Katze" von "Tier" abzuleiten oder ähnliches.
Ein ähnlicher Gedankengang, prinzipiell gesehen, steckt übrigens hinter Entgegnungen anderer wie "schon die Voraussetzungen sind falsch".
-
Xin schrieb:
Ich sehe diese Diskussion ähnlich, ich bezweifle dass jemand eine nachvollziehbare Begründung finden wird, warum ein Algorithmus, der sich eben nicht am Objekt orientiert, weil virtual fehlt, als objektorientiert zu bezeichnen wäre.
Erklär mir mal kurz ob du folgendes System als OO betrachtest - es ist teil einer Ajax Library die ich verwende.
Es gibt Objekte vom Typ "XHR" diese beinhaltet grundlegende Fähigkeiten um mit anderen Servern über HTTP zu kommunizieren. Darunter die funktion "call" um eine Remote Funktion aufzurufen.
Dann gibt es Objekte vom Typ "FooXHR" der die gleichen Methoden beinhaltet wie "XHR". Darunter auch eine "call" Funktion die aber etwas komplexer ist und Daten per JSON codiert und decodiert um komplexe Funktionsaufrufe zu ermöglichen - die Signatur von FooXHR::call und XHR::call ist gleich.
Es gibt auch Objekte vom Typ BarXHR, wo die call Funktion die Daten mit etwas komplett anderen codiert. Und wenn ich will kann ich weitere Objekte erstellen die wieder die Daten komplett anders codieren.
Ich denke das würde man als OO Design ansehen, oder?
Das lustige dabei ist aber: es ist in JavaScript geschrieben: keine Klassen, kein Virtual.
Ein anderes Beispiel sind C++ Templates. Statische Polymorphie
Wenn du sagst OOP ist eine Technik die mit anderen Techniken verknüpft werden kann - was genau ist dann OOP? Datahiding kein Bestandteil der OOP? Polymorphie aber schon? Schwer zu trennen das ganze.
Ich persönlich mag folgende Definition am liebsten:
Objektorientierung ist, sich an Objekten zu orientieren.Es gibt einfach kein Feature dass ich unbedingt zur OO zählen muss. Datahiding - ich finde zB FILE* in C objektorientiert. Da ist 0 Datahiding. Polymorphie? Klassen? Ich schreibe OO Code in Javascript.
-
scrub schrieb:
Xin schrieb:
Für wau() und miau() braucht man kein OOP. Abstrahiert man das Problem, hat es allerdings Sinn eine abstrakte Form von wau() und miau() virtuell zu gestalten.
Bereits an dem Punkt scheiden sich beide Erklärungsvarianten: Gemäß den mir bekannten Definitionen ist es bereits objektorientiert, wenn ich eine Klasse "Katze" schreibe, der ich bestimmte Eigenschaften (Rasse, Geschlecht) und Funktionen (Fell abziehen, toasten) zuordne.
Das ist exakt die Frage, die ich hustbaer gestellt habe.
Wenn Du eine Klasse als Namespace nutzt, kannst Du eigentlich auch die ungarische Notation verwenden und gleich C verwenden:katze_miau( struct Katze * );
Du gewinnst nichts. Es ist wahrscheinlich, dass das Programm in der C-Variante sogar schneller wird.
scrub schrieb:
Es ist hingegen nicht erforderlich, "Katze" von "Tier" abzuleiten oder ähnliches.
Ein ähnlicher Gedankengang, prinzipiell gesehen, steckt übrigens hinter Entgegnungen anderer wie "schon die Voraussetzungen sind falsch".Ich stimme ich, dass hier ein ähnlicher Gedankengang vorliegt und ich hoffe, das auch Jesper Deine Argumentation über die Deine letzten Postings liest und kommentiert.
Wo liegt für Dich denn der Sinn objektorientiert zu arbeiten, wenn es das Programm dadurch eventuell langsamer wird und Du nur einen einzigen Datentyp hast, an dem Du Dich orientieren kannst?
Weiterhin haben schon einige Leute nach meinem Reply auf hustbaers Posting geschrieben, aber keiner hat bisher meine Frage zu eurer Vorstellung beantwortet.
-
Xin schrieb:
tier.Tier::Funktion( typ Parameter )
Das unterscheidet sich von
tier_Funktion( Tier * tier, typ Parameter )
nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?
Der Unterschied ist ganz einfach, und genau das habe ich doch schon (implizit) gesagt: Die erste Funktion ist ganz eindeutig mit dem Objekt verbunden. Im zweiten Fall gibt es jedoch "irgendwo" "irgendeine" Funktion, die man selbst, ohne, daß man es im Quelltext vorher sieht, mit dem Tier in Verbindung bringen muß.
Und um das nochmal ganz klar zu sagen: Bereits diese Zuordnung ("mit Objekten der Klasse 'Katze' kann die Funktion 'Fell abziehen' durchgeführt werden") ist Objektorientierung. Im Sinne der Definitionen ... und so weiter.
Desweiteren würde ich mich im Fall 1 einfach darauf verlassen (dürfen), daß die Funktion des Tiers keinen Unfug anstellt. In Fall 2 mag die Funktion möglicherweise durch ihren Namen andeuten, was sie machen soll- aber darauf verlassen würde ich mich nicht.Im Übrigen kann ich weder Java noch C#.
-
Shade Of Mine schrieb:
Xin schrieb:
Ich sehe diese Diskussion ähnlich, ich bezweifle dass jemand eine nachvollziehbare Begründung finden wird, warum ein Algorithmus, der sich eben nicht am Objekt orientiert, weil virtual fehlt, als objektorientiert zu bezeichnen wäre.
Erklär mir mal kurz ob du folgendes System als OO betrachtest - es ist teil einer Ajax Library die ich verwende.
Es gibt Objekte vom Typ "XHR" diese beinhaltet grundlegende Fähigkeiten um mit anderen Servern über HTTP zu kommunizieren. Darunter die funktion "call" um eine Remote Funktion aufzurufen.
Dann gibt es Objekte vom Typ "FooXHR" der die gleichen Methoden beinhaltet wie "XHR". Darunter auch eine "call" Funktion die aber etwas komplexer ist und Daten per JSON codiert und decodiert um komplexe Funktionsaufrufe zu ermöglichen - die Signatur von FooXHR::call und XHR::call ist gleich.
Es gibt auch Objekte vom Typ BarXHR, wo die call Funktion die Daten mit etwas komplett anderen codiert. Und wenn ich will kann ich weitere Objekte erstellen die wieder die Daten komplett anders codieren.
Ich denke das würde man als OO Design ansehen, oder?
Das kommt drauf an, ob die Objekte von einander abhängig sind. Wenn sie von einander abhängig sind und über eine standardisierte Schnittstellenklasse verfügen, über die man die Funktionen erreichen kann, spricht das für OOP, da die Schnittstelle ja abhängig vom Objekttyp die Funktionen aufruf:
Wenn bla vom Typ "Schnittstelle XHR" ist und bla.Snafu() die Funktion FooXHR.Snafu() aufruft, weil das Objekt auf das bla referenziert ein FooXHR-Objekt ist, dann ist das OOP.Wenn es nur drei unabhängige Datentypen sind, die zufälligerweise die gleichen Funktionsnamen haben und die dadurch austauschbar werden, dann hat das nichts mit OOP zu tun. Das geht eher in Richtung Template, womit nicht das C++-Template gleichzusetzen ist.
Shade Of Mine schrieb:
Das lustige dabei ist aber: es ist in JavaScript geschrieben: keine Klassen, kein Virtual.
Das ist schade, ich würde es in OOP umschreiben, es wäre prädestiniert dafür.
Shade Of Mine schrieb:
Ein anderes Beispiel sind C++ Templates. Statische Polymorphie
Beispiel wofür?
Shade Of Mine schrieb:
Wenn du sagst OOP ist eine Technik die mit anderen Techniken verknüpft werden kann - was genau ist dann OOP? Datahiding kein Bestandteil der OOP? Polymorphie aber schon? Schwer zu trennen das ganze.
Eigentlich nicht. Das Überschreiben von virtuellen Funktionen ist erforderlich, sonst könnte man nicht objektabhängig unterschiedliche Funktionen rufen. Objektorientierte Abläufe sind ist ja genau der Hintergrund, weshalb man virtuelle Funktionen überschreibt.
Das Überschreiben von statischen Funktionen oder das Überladen beliebiger Methoden ist dafür nicht erforderlich.Shade Of Mine schrieb:
Ich persönlich mag folgende Definition am liebsten:
Objektorientierung ist, sich an Objekten zu orientieren.*lach* Die Definition ist auf den ersten Blick gar nicht mal übel.
Sie macht aber bei genauerem Hinsehen keinen Sinn, weil alles, was nicht void ist, ein Objekt ist. Würde man sich nicht an irgendwelchen Daten orientieren, bräuchte man auch man auch keine Programme zu schreiben.
-
scrub schrieb:
Xin schrieb:
tier.Tier::Funktion( typ Parameter )
Das unterscheidet sich von
tier_Funktion( Tier * tier, typ Parameter )
nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?
Der Unterschied ist ganz einfach, und genau das habe ich doch schon (implizit) gesagt: Die erste Funktion ist ganz eindeutig mit dem Objekt verbunden. Im zweiten Fall gibt es jedoch "irgendwo" "irgendeine" Funktion, die man selbst, ohne, daß man es im Quelltext vorher sieht, mit dem Tier in Verbindung bringen muß.
Und um das nochmal ganz klar zu sagen: Bereits diese Zuordnung ("mit Objekten der Klasse 'Katze' kann die Funktion 'Fell abziehen' durchgeführt werden") ist Objektorientierung. Im Sinne der Definitionen ... und so weiter.katze_fellabziehen( Katze * ) - hier ist die Zuordnung zur Katze eindeutig.
Weiterhin ist das exakt die Signatur, die Katze::FellAbziehen( void ) im Objektfile erhalten wird.
Es ändert sich nichts, unabhängig davon, was Du persönlich für Dich als vertrauenswürdiger oder übersichtlicher empfindest, verwurstet der Compiler beides identisch.scrub schrieb:
Desweiteren würde ich mich im Fall 1 einfach darauf verlassen (dürfen), daß die Funktion des Tiers keinen Unfug anstellt. In Fall 2 mag die Funktion möglicherweise durch ihren Namen andeuten, was sie machen soll- aber darauf verlassen würde ich mich nicht.
Darauf kannst Du Dich ebenso verlassen, wie bei bei einer Methode.
Solange Du es nicht selbst geschrieben hast, musst Du Dich darauf verlassen, dass die Funktion ihrer Dokumentation entsprichst. Das gilt ebenso für Methoden.
Wenn Du die Zuordnung selbst machst, musst Du Dich darauf verlassen, dass Du weißt, was Du tust und wie Du Dein Programm aufbaust - unabhängig ob Funktion oder Methode.So, reicht langsam für heute - ich geh ins Bett.
-
Xin, das ist die beste definition von OOP die ich jemals gehoert habe.
Klassenbasiert ist alles, was mit Datenstrukturen zu tun haben, die ausschließlich auf den aktuell verwendeten Datentyp - eben die Klasse - fixiert sind und Daten eben klassifizieren. Du könntest Dir in dem Zusammenhang kurz Gedanken machen, warum das Schlüsselwort in allen gängigen Sprachen "class" heißt und nicht "object".
Katzen gehören zur Klasse der Tiere, welche zur Klasse der Lebewesen gehören. Bis hierhin gibt es noch nichtmal ein Objekt, keine existierende Katze, kein existirendes Tier, lediglich die Feststellung, dass derartige Objekte - sollten sie irgendwann existieren - irgendwie klassifiziert werden und dass zwischen Katzen und Tieren eine gerichtete Verbindung besteht.
Beim Zugriff auf die Objekte orientiert sich die Sprache an der Klasse, die man zur Zeit betrachtet. Ein Tier ist eine andere Klasse als eine Katze und Tiere machen alles wie Tiere und Katzen machen alles wie Katzen. Katzen sind Tiere und eine Objekt, das als Tier aufgefordert wird etwas zu tun, interessiert sich nicht die Bohne, dass Katzen das lieber anders machen würden.
Alles statisch, eben nicht objektorientiert, aber eben mit 'class'es klassifiziert.Objektorientiert wird das ganze in dem Moment, wo es eben nicht mehr um die Klasse, sondern um die Klasseninstanz - das Objekt - geht. Eine Katze ist eine Instanz der Klasse Tier und genauso eine Instanz der Klasse Lebewesen. Da jedoch nicht mehr alleine auf die Klassifizierung Wert gelegt wird, sondern man sich am wirklichen Typ der Datenstruktur - des Objektes - orientiert, verhält sich ein Objekt Katze der Klasse Tier wie eine Katze, genauso wie ein Objekt Katze der Klasse Lebewesen sich wie eine Katze verhält.
Man arbeitet objektorientiert und damit sich das von klassenorientierter Programmierung unterscheidet, nehme man in C++ das Schlüsselwort "virtual".Um etwas zu klassifizieren kann man in C++ "class" nehmen. Es geht in C aber genauso gut mit "struct".
Nur weil man der Sprache mitteilen kann, dass Funktionen einer Datenstruktur zugehörig ist, wird daraus kein OOP.
Eine "class" ist eine Struktur mit einem eigenen Namensraum und beim Aufruf von Methoden steht das erste Argument links vom Methodennamen. Mehr ist das nicht und solange da kein virtual drin steht, ist es problemlos und ohne Aufwand in C abzubilden, weil man keine OOP Unterstützung benötigt.Der Link http://paulgraham.com/reesoo.html ist zwar schoen, aber da stimme ich Xin zu, dass vieles davon nicht zu OOP gehoert, bzw. OOP auch ohne diese Techniken funktioniert.
Zu der Konstante: Es spielt keine Rolle ob ein Algorithmus k langsamer ist als ein anderer. Vielleicht vor 20 Jahren, aber doch nicht heute. Lernt man im ersten Semester bei Komplexistaetslehre (oder halt ein aehnliches Fach).
Sprache 250MHz R1000 400 MHz Pentium II Athlon 64 3200 C 0,36s 0,30s 0,054s C++/STL/deque 2,60s (*7,22) 11,20s (*37,33) 0,395s (*7,31) C++/STL/list 1,70s (*4,72) 1,50s (* 5,00) 0,247s (*4,57)
Hast du auch die deque und list mit all ihren Moeglichkeiten in C nachgebildet?
Ehm ja... die O-Notation ist ein theoretisches Werkzeug. Und man kann damit toll Algorithmen vergleichen (sogar ohne sie konkret zu implementieren). Und dass man dabei die Konstanten plattklopfen kann ist echt praktisch. Aber gerade die Konstanten sind in der Realität eben doch von Bedeutung. Die kann man da nicht einfach unter den Tisch fallen lassen. Die O-Notation hilft nicht irgendwas schneller oder langsamer zu machen.
Bitte? Ob ein Algo also O(n) ist oder O(n^2) spielt also keine Rolle, aber hauptsache man vergisst die Konstanten nicht? Das sind diese typischen "ich hacke alles in Asm, weil da der Flaschenhals ist"-Leute die hier in RudP nach Hackertipps fragen.
Es ging hier aber in keiner Weise um Komplexität, sondern um konkrete Laufzeit: "Faktor 5-10 langsamer" macht aus 5s Laufzeit eben 25-50s Laufzeit.
Und dann kommt DEvent und behauptet, das wäre vollkommen bedeutungslos, indem er plötzlich Komplexität ins Spiel bringt.Sorry, habe ein Fehler gemacht. Ich meinte natuerlich nicht um Faktor k groesser, sondern um eine Konstante k groesser.
Also nichtO(k * n) = O(n)
O(k * n^p) = O(n^p)
O(k * p^n) = O(p^n)
usw.Das ist natuerlich falsch.
Sondern:
O(k + n) = O(n)
O(k + n^p) = O(n^p)
O(k + p^n) = O(p^n)
usw.Prozedural: man hat bestimmte Funktionen/Prozeduren die man aufruft um bestimmte Dinge zu erledigen. Diesen gibt man bestimmte Parameter mit.
Als "Auswahlkriterium" welcher Code wirklich ausgeführt wird dient der Name der Prozedur und sonst nix (ggf. noch die Signatur, wenn man Features wie Overloading verwendet).OO: man schickt eine Nachricht an ein Objekt. Diese Nachricht besteht aus einem "Verb" + ggf. zusätzlichen Parametern.
Als "Auswahlkriterium" welcher Code wirklich ausgeführt wird dient das "Verb" der Nachricht + das Objekt an welches man die Nachricht geschickt hat.Genau das versucht ja Xin uns zu vermitteln.
Wenn man diese Definition von OO(P) verwendet heisst das noch lange nicht dass man hier irgendwelche abstrakten Klassen, Polymorphie oder virtuelle Aufrufe braucht. Wenn ein Programm so entworfen ist dass "die Auswahl des auszuführenden Codes" immer zur Compile-Zeit erfolgen kann (ohne natürlich den "falschen" Code auszuwählen), dann ist das kein Grund warum das Programm nichtmehr "OO" wäre. Logischerweise kann man viele Dinge damit nicht machen, oder muss sie zumindest ganz anders machen als wenn man z.B. virtuelle Aufrufe verwenden würde.
Genau das ist eben keine OOP. Weil sich die Klassen eben nur als ein Namespace verhaelt. Dem Compiler ist es total egal, ob da ein Class steht oder nicht. Tausche einfach das Class durch namespace aus, es ist das gleiche. Ebenso koentest du einfach das class durch ein Namens-Praefix austauschen.
Jetzt sag ich Dir mal, was ich zuallermeist gehört habe und was (nicht deshalb!) sich auch logisch anhört:
Objektorientiert ist, wenn man statt einem Haufen Daten und einem anderen Haufen Funktionen ganz klar bestimmten Daten(-typen) bestimmte Funktionen zuordnet, man also bereits im Quelltext genau sehen kann, daß miau() zur Katzenklasse und wau() zur Hundeklasse gehört- statt sich jedesmal selbst die passende Funktion rauszuschen, die man gerade braucht.
Die Begrifflichkeiten virtueller Funktionen und der restliche Krempel, dies alles kam in diesem Erklärungen des Themas OO _nie_ vor, kein einziges Mal. Ich lese davon in Deinen Beiträgen zum ersten Mal.
Und bevor Du jetzt wieder lospapmpst: Ich habe nicht behauptet, daß Du Unfug redest. Aber Deine Argumentationsbasis ist aus meiner Sicht relativ schmal.Das ist echt komische Definition. Nach dieses Definition muesste das auch OOP sein:
namespace katze { void miau(); } namespace hund { void wau(); }
Das kommt drauf an, ob die Objekte von einander abhängig sind. Wenn sie von einander abhängig sind und über eine standardisierte Schnittstellenklasse verfügen, über die man die Funktionen erreichen kann, spricht das für OOP, da die Schnittstelle ja abhängig vom Objekttyp die Funktionen aufruf:
Wenn bla vom Typ "Schnittstelle XHR" ist und bla.Snafu() die Funktion FooXHR.Snafu() aufruft, weil das Objekt auf das bla referenziert ein FooXHR-Objekt ist, dann ist das OOP.Polymorphie ist ein heikles Thema in JS. Es ist moeglich eine Schnittstelle zu definieren und dann erst wenn man den Typen des Objektes kennt, zu entscheiden welche Methode aufgerufen wird.
function Basisklasse(eigenschaft) { this.eigenschaft = eigenschaft; this.macheWas = basisklasseMacheWas; } function basisklasseMacheWas() { alert(this.eigenschaft); } function Katze(eigenschaft) { this.constructor(eigenschaft); this.macheWas = new function() { alert("katze hat: " + this.eigenschaft); } } Katze.prototype = new Basisklasse(); katze = new Katze("Beine");
Man kann aber nicht mehr von dem Objekt katze die Methode Basisklasse#machWas() aufrufen. Oder kann man? Hab ueberhaupt nichts in dieser Richtung gefunden.
-
Xin schrieb:
Shade Of Mine schrieb:
Das lustige dabei ist aber: es ist in JavaScript geschrieben: keine Klassen, kein Virtual.
Das ist schade, ich würde es in OOP umschreiben, es wäre prädestiniert dafür.
Aber warum ist es nicht OO? Das ist die essentielle Frage.
Ich habe keine Klassen - also keine Ableitung. Aber dennoch ist FooXHR im übertragenen Sinn eine Subklasse von XHR. Es beinhaltet nämlich alle Methoden die XHR auch beinhaltet - bis auf call, welches im übertragenen Sinn überschrieben wurde und somit im übertragenen Sinn so etwas wie Polymorphie bietet.Lediglich dass ich die Tools wie Klasse und virtual nicht habe. Objekte vom Typ FooXHR sind einfach klone des Prototyps von XHR.
In C++ würde man es mit Vererbung und virtuellen Funktionen machen - aber diese Features habe ich in JavaScript nicht - aber dennoch kann ich etwa die selbe Funktionalität bieten. Prototype basierte Sprachen haben eben einen Fokus auf Objekte - es gibt keine Klassen sondern nur Objekte.
Warum ist das alles jetzt nicht OO? JavaScript bietet keine Klassen und ohne Klassen kein virtual. Dennoch ist Javascript Code sehr an Objekten orientiert.
Shade Of Mine schrieb:
Ein anderes Beispiel sind C++ Templates. Statische Polymorphie
Beispiel wofür?
Dass es nicht nur Laufzeit Polymorphie gibt wie du scheinbar denkst. Standard Beispiel ist wohl:
class Shape { public: virtual void draw()=0; }; class Circle : public Shape{ public: void draw(); }; class Triangle : public Shape{ public: void draw(); }; void foo(Shape* s) { s->draw(); }
Das ist ein Standard Beispiel für Polymorphie, oder?
Nun, das ganze ohne virtual und ohne vererbung:class Triangle { public: void draw(); }; class Circle { public: void draw(); }; template<typename Shape> void foo(Shape s) { s.draw(); }
Selbe Funktionalität, selber Inhalt - nur eben statisch gelöst.
Shade Of Mine schrieb:
Eigentlich nicht. Das Überschreiben von virtuellen Funktionen ist erforderlich, sonst könnte man nicht objektabhängig unterschiedliche Funktionen rufen. Objektorientierte Abläufe sind ist ja genau der Hintergrund, weshalb man virtuelle Funktionen überschreibt.
Ziemlich auf Java/C++ fixiert von der Idee her. Wie gesagt: es gibt OO Sprachen die keine Klassen bieten. Wie kann ich ohne Klasse eine virtuelle Funktion haben? Oder sind Klassen ebenfalls für OOP nötig?
Sie macht aber bei genauerem Hinsehen keinen Sinn, weil alles, was nicht void ist, ein Objekt ist. Würde man sich nicht an irgendwelchen Daten orientieren, bräuchte man auch man auch keine Programme zu schreiben.
Selbst wenn alles ein Objekt wäre - meine Definition verlangt dass man sich an diesen Objekten orientiert, sprich das Objekt selber ins Zentrum schieben.
In normalen prozedualen Code hat man natürlich auch Variablen die du vielleicht Objekte nenen willst, aber sie bestimmen nicht das Programmverhalten. Ich denke in einem OOD geht es nur darum in Objekten zu denken. Deshalb ist FILE* aus C für mich ein OOD. Und auch JavaScript ist in meinen Augen eine OO Sprache. Denn ich fixiere mich bei der Programmierung auf die Objekte - anders als zB in altem C wo man eher auf Daten und Funktionen fixiert ist.
Ich denke es ist ein Fehler ein Feature zu nehmen und zu sagen: das ist OO. Der denn ich kenne kein einziges OO Feature ohne dem es nicht auch geht. Ich brauche keine virtuellen Funktionen um OO zu programmieren. Lisp zum Beispiel bietet keine virtuellen Funktionen an. Man hat dort stattdessen Multimethods - die aber einen ähnlichen Zweck erfüllen. Dennoch gilt Lisp als eine der ersten Objektorientierten Sprachen.
In meinen Augen ist OOP eine Denkweise und es gibt nahezu unendlich viele Tools die es mir erleichtern dieser Denkweise im Code Ausdruck zu verschaffen. Dynamische Polymorphie ist ein Teil davon - virtual erlaubt es mir dem Objekt das Verhalten festlegen zu lassen. Die Idee ist: Ich sage object.gib_laut() und das Objekt weiß ob es jetzt bellen oder miauen soll. Ob das ganze nun über Prototypen, laufzeit polymorphie mit virtual, statische Polymorphie mit Templates, Multimethods oder funktionszeiger gelöst wurde tut der Denkweise, bzw dem was ich damit im Code Aussage nichts zur Sache.
Denn im Prinzip sind virtual Funktionen in C++ auch nichts anderes als wenn man Funktionszeiger in C nehmen würde. Lediglich der Compiler übernimmt einem die Arbeit und bietet gewissen Komfort in der Benutzung an. Aber im Prinzip kann man das Shape Beispiel in C genauso schreiben:
struct Shape { void (*draw)(Shape*); void* extended; }; Shape create_circle() { Shape s; s.draw=circle_draw; s.extended=bla; return s; } Shape create_triangle() { Shape s; s.draw=triangle_draw; s.extended=bla; return s; } void foo(Shape s) { s.draw(&s); }
Denn viel anderes macht der C++ compiler aus dem Code auch nicht. Wo setzt man nun mit der Definition an? Alles was der Compiler macht ist Magie und ich darf es nicht händisch machen damit es OO ist?
Und was ist mit anderen Features? Warum ist virtual besser als Multimethods bzw warum ist es mehr OO? Warum brauche ich Vererbung und warum ist der Prototype Ansatz weniger OO als der Vererbungsansatz?
Es gibt mehr Sprachen als C++ und Java. Und genauso gibt es mehrere Möglichkeiten ein Problem zu lösen. Wenn nur C++ und Java OO sind - was sind dann Lisp, JavaScript, Self,...
Bereits in C++ und Java hat man enorme Unterschiede in der OO-Denkweise. In Java hat man zum Beispiel ein Interface Comparable für Klassen die Vergleiche zulassen. In C++ hat man die exakt selbe Funktionalität mit globalen operatoren. Ist der Comparable Ansatz jetzt mehr OO als der operator== Ansatz?
-
Das trifft es ganz gut:
http://www.heise.de/ix/artikel/2001/04/194/Spricht man von der Existenz polymorpher Typen, so trifft dies in Bezug auf JavaScript nicht ganz den Punkt: Da es keine Typisierung gibt, sind alle Instanzen in gewisser Weise polymorph. Zudem ist späte Bindung unter JavaScript Standard, da stets erst zur Laufzeit ermittelt wird, an welches Objekt eine Methode gebunden wird. Das Problem liegt bei JavaScript an einer anderen Stelle: Die Sprache ist in Bezug auf Polymorphie eher zu wenig restriktiv; deshalb können durchaus Botschaften an einzelne Objekte geschickt werden, die in der Klassenhierarchie beziehungsweise Prototypenkette in keinerlei Relation stehen. Einzige Bedingung: die Instanzen bieten jene Methode an. Somit ist semantische Substituierbarkeit in diesem Kontext nur gegeben, wenn der Programmierer besondere Sorgfalt beim Einsatz von Polymorphie walten lässt und sie nicht wahllos einsetzt.
Achja und es gibt sehr wohl Vererbung in Javascript.
Das ist ein Standard Beispiel für Polymorphie, oder?
Nun, das ganze ohne virtual und ohne vererbung:class Triangle { public: void draw(); }; class Circle { public: void draw(); }; template<typename Shape> void foo(Shape s) { s.draw(); }
Selbe Funktionalität, selber Inhalt - nur eben statisch gelöst.
Eben nicht die selbe Funktionalitaet. Du kannst nicht, waehrend das Programm laeuft, den Typen austauschen. Du kannst es einmal vom Compiler uebersetzen und dann ist es in Stein gemeiselt.
-
DEvent schrieb:
Achja und es gibt sehr wohl Vererbung in Javascript.
erklär mal bitte wie
Eben nicht die selbe Funktionalitaet. Du kannst nicht, waehrend das Programm laeuft, den Typen austauschen. Du kannst es einmal vom Compiler uebersetzen und dann ist es in Stein gemeiselt.
Genauso kann man aber auch sagen dass Objekte in C++ nicht die selbe Funktionalität bieten wie in Java. Es fehlt zB Reflection. Ich kann in C++ zB nicht ohne Probleme eine neue Klasse laden.
Die Frage ist: wo setzt man die Trennstriche?
Ebenso die Polymorphie in JavaScript - klar muss der Programmierer darauf achten keine Interfacefehler zu machen - selbes gilt aber auch für C++. Die Frage ist hier: bedeutet OO dass man dem Programmierer verbietet diverse Möglichkeiten zu nutzen?Aber bitte, erklär mir mal warum JavaScript nicht OO ist und warum Lisp nicht OO ist. Warum ist dynamische Polymorphie essentiell für OO und statische Polymorphie nicht? Warum sind Klassen ein sinnvollerer OO Ansatz als Prototypes?
Wäre schön wenn du mir das erklären könntest.
-
Klar ist es das Hauptziel der OOP, dass man Vererbung und Laufzeit-Polymorphie verwendet. Aber Code der nur Datenkapselung enthält ist auch OOP, weil sich das auch an den Objekten orientiert. Datenkapselung ist halt "Anfänger OOP" und Laufzeit-Polymorphie mehr "Experten OOP".
Xin schrieb:
Cpt. Nukem schrieb:
Aber was macht OOP in der Praxis aus? Viel Prozent der Zeit gehen für sowas drauf? 30, 3, 0.3 oder noch weniger? Gibts dazu eine verlässliche Quelle?
Man geht davon aus, dass ein C++ Programm 5-10mal langsamer läuft als ein entsprechndes C Programm.
Das ist aber sehr programmabhängig, die Zahlen sind also bestenfalls wage Anhaltspunkte, ich habe sie aber schon in verschiedenen Büchern zu dem Thema gesehen. Es liegt auch nicht vorrangig an OOP, sondern an der Tatsache, dass C++ Compiler aufwendiger sind als C-Compiler, entsprechend auch die Optimierung aufwendiger wird.Und ohne Compiler unterschied? Wieviel machen diese paar Befehle mehr für nen virtuellen Methodenaufruf aus, im Vergleich zum restlichen Programm?
-
Cpt. Nukem schrieb:
Und ohne Compiler unterschied? Wieviel machen diese paar Befehle mehr für nen virtuellen Methodenaufruf aus, im Vergleich zum restlichen Programm?
0, wenn der compiler smart genug waere es auf die qualitaet von c zu optimieren, gebe es keinen unterschied.
-
Xin schrieb:
tier.Tier::Funktion( typ Parameter )
Das unterscheidet sich von
tier_Funktion( Tier * tier, typ Parameter )
nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?
gibt keinen. die letztere Funktion würde man in C für genau diesen Fall nutzen. Class und alles was dazugehört ist nur ein syntaxgimmik. Der Compiler macht am Ende eh dasselbe draus(siehe Comeau, das zum Thema geschwindigkeit btw). Was am Ende zählt ist nur die Denkweise.
OOP ist für mich ein Programmierstil, bei dem sich Objekte gegenseitig Informationen zuschieben und diese dann verarbeiten. Wie die einzelnen Objekte im jeweiligen Fall implementiert sind ist wurscht, idealerweise sind sie eh komplett austauschbar. Was ich nun als Objekt bezeichne ist von Sprache zu Sprache unterschiedlich.In C ist zb FILE ein gutes Objekt. man kann es öffnen, schließen, daten mit ihm ein und auslesen...
In C++ könnte deine Tier Funktion so aussehen:
template<class Tier,class Typ> tier_function(Tier,Typ){...}
das ist das C++ argument gegen den overhead von virtuellen funktionen: statische polymorphie. Die Fälle in denen man Polymorphie wirklich braucht sind sehr gering. In vielen Sprachen braucht man sie aber um Objekte "zusammenstecken" zu können, also Das Klasse Foo Objekte mit dem Interface Bar nutzt um die Drecksarbeit zu erledigen.
Ein Beispiel dafür was ich Meine ist hier: http://de.wikipedia.org/wiki/Bridge_(Entwurfsmuster)#UML-Diagramm.
In C++ bei verwendeter statischer Polymorphie werden diese Abstrakten Interfaces nutzlos(in dem Fall vom link oben der "implementierer"), um genauer zu sein sie werden durch eine Interface absprache ersetzt. "Ich benutz methode Foo, also muss diese vom Objekt bereitgestellt werden". Mit dem nächsten Standard werden die Concepts kommen, die statische version des Abstrakten Interfaces.Ist dies nun weniger Polymorphie, nur weil ich den zeitpunkt änder, wann die Objekte zusammengesteckt werden? Ob ich nun zur Laufzeit eine sortiere Liste mit einer arraykern erstelle oder schon zur Compilezeit macht keinen großen Unterschied(ausser es ist zu einem dieser zeitpunkte erforderlich)
-
Das ist aber ein sehr eingeschränkter Blick auf die Objektorientierung Wenn du wirklich so wenig Unterschiede zwischen Compilierzeit und Laufzeit siehst, kannst du gleich zur Template Metaprogrammierung wechseln - das erzeugt extrem kompakte und schnelle Progamme (daß man da zur Laufzeit nichts mehr beeinflussen kann, stört ja niemanden :D).
Der Vorteil der dynamischen Polymorphie ist ja, daß du zur Laufzeit entscheiden kannst, was für ein Objekt tatsächlich betroffen ist - du hast einen Zeiger auf ein Fahrzeug und rufst dessen Methode starte_motor() auf, dann findet der Compiler selber die richtige Methode, je nachdem ob der Zeiger auf einen PKW, ein Motorboot oder einen Jumbo-Jet zeigt. Rein statisch müsstest du dich beim Compilieren festlegen, mit was für einem Fahrzeugtyp du dich beschäftigen willst - und wenn du feststellst, daß du doch nicht mit PKWs, sondern mit Jumbo-Jets arbeiten willst, mußt du das Programm neu compilieren (vom nötigen Aufwand, um PKWs und Jets gemischt nutzen zu können, will ich gar nicht reden).
Und um das ganze mal zusammenzufassen:
Virtuelle Methoden sind langsamer als "reguläre" Methoden, aber flexibler - und wenn du diese Flexibilität brauchst, sind sie allemal schneller als jeder Versuch, sie von Hand nachzubauen.(PS: Sorry, wenn ich bereits formulierte Erkenntnisse wiederhole - ich hab' möglicherweise etwas den Anschluß verloren)
-
CStoll schrieb:
Das ist aber ein sehr eingeschränkter Blick auf die Objektorientierung Wenn du wirklich so wenig Unterschiede zwischen Compilierzeit und Laufzeit siehst, kannst du gleich zur Template Metaprogrammierung wechseln - das erzeugt extrem kompakte und schnelle Progamme (daß man da zur Laufzeit nichts mehr beeinflussen kann, stört ja niemanden :D).
es generiert eher aufgeblaehte programme.
-
CStoll schrieb:
Und um das ganze mal zusammenzufassen:
Virtuelle Methoden sind langsamer als "reguläre" Methoden, aber flexibler - und wenn du diese Flexibilität brauchst, sind sie allemal schneller als jeder Versuch, sie von Hand nachzubauen.Ich hab ja geschrieben: " wenn man sie wirklich braucht" und danach ein beispiel genannt, wobei sie häufig genutzt wird, ohne dass man sie wirklich braucht und gefragt, ob der C++ weg der Statischen Polymorphie in dem Fall weniger OOP ist.
Entschuldige, wenn ich nicht ganz eindeutig war
-
Wenn du es so siehst, macht es Sinn. Aber das Bridge-Pattern ist nicht wirklich ideal als Gegenbeispiel für dynamische Polymorphie (will sagen: es hängt von den Randbedingungen ab, ob du sowas statisch aufbauen kannst oder nicht)
-
DEvent schrieb:
Ehm ja... die O-Notation ist ein theoretisches Werkzeug. Und man kann damit toll Algorithmen vergleichen (sogar ohne sie konkret zu implementieren). Und dass man dabei die Konstanten plattklopfen kann ist echt praktisch. Aber gerade die Konstanten sind in der Realität eben doch von Bedeutung. Die kann man da nicht einfach unter den Tisch fallen lassen. Die O-Notation hilft nicht irgendwas schneller oder langsamer zu machen.
Bitte? Ob ein Algo also O(n) ist oder O(n^2) spielt also keine Rolle, aber hauptsache man vergisst die Konstanten nicht? Das sind diese typischen "ich hacke alles in Asm, weil da der Flaschenhals ist"-Leute die hier in RudP nach Hackertipps fragen.
Liebes Kind DEvent. Bitte sei doch ruhig wenn sich Diplominformatiker über Dinge unterhalten von denen Du offensichtlich keine Ahnung hast. -- Danke!
Zur Erinnerung zitiere ich auch noch den restlichen Unsinn den Du verzapft hast:
DEvent schrieb:
O(k * n) = O(n)
O(k * n^p) = O(n^p)
O(k * p^n) = O(p^n)
usw.Das ist natuerlich falsch.
Sondern:
O(k + n) = O(n)
O(k + n^p) = O(n^p)
O(k + p^n) = O(p^n)
usw.Autsch