OOP: soll man jetzt alles in ne Klasse packen oder watt?
-
^ ist halt das bitweise XOR, soviel ich weiss nicht nur in Java sondern auch in C++.
-
byto schrieb:
^ ist halt das bitweise XOR, soviel ich weiss nicht nur in Java sondern auch in C++.
geh einfach mal davon aus, daß das bekannt ist, und man sich dennoch 2.34^32.3456 zum potenzieren wünscht. dafür kann ^ ruhig die bedeutung von xor verlieren. braucht eh keiner, weil xor hübscher ist.
int x = 3 xor 4;
-
Um ehrlich zu sein, ist mir das ziemlich wurscht. Ich brauche weder pow noch sqrt noch irgendwelche anderen höheren mathematischen Funktionen häufig. Der Anteil funktionaler Programmteile tendiert bei mir in der Regel gegen null. Aber wenn ich mal C++ lerne, dann werde ich auch mal einen Taschenrechner programmieren und mich des Lebens freuen über diese großartige Operatorüberladung und so weiter... :p
-
Das sqrt-Beispiel ist ein gutes Beispiel dafür, dass es - nur weil es eine 'objektorientierte' Sprache ist - nicht immer sinnvoll ist, alles objektorientiert zu machen (bzw. dass Java eben doch keine 100% oo-Sprache ist, sonst ginge ja 1.1.sqrt() )
Trotzdem ist es letztlich kein Unterschied, ob sqrt jetzt in einem namespace 'math' oder als statische Funktion in einer Klasse 'Math' liegt. C++ erlaubt einem hier halt genauer auszudrücken was man will, was prinzipiell gut ist, das ganze aber auch schwieriger macht. D.h. C++ hat zwar objektiv die Möglichkeit es besser auszudrücken, aber alle die C++ verwenden müssen diese Möglichkeit auch kennen und dieselbe Auffassung über diese Möglichkeit haben. Dazu braucht man aber halt mehr Erfahrung als in Java, wo es eben nur eine Möglichkeit gibt, die zwar nicht so perfekt passt aber im Endeffekt dasselbe erreicht.
Das kann man vielleicht allgemein so sagen (*duck*):
Ein guter C++Programmierer kann in C++ wahrscheinlich 'bessere' (im Sinn von ausdrucksstärkere Formulierungen und allem was daraus in Sachen Wartbarkeit etc. erwächst) Programme schreiben als ein guter Java-Programmierer, weil ihm die Sprache mehr Möglichkeiten dafür lässt. Dafür kann ein schlechter C++Programmierer sicherlich auch schlechtere Programme als ein schlechter Java-Programmierer schreiben.
(PS. dabei red ich zuerst mal ausschließlich von den Sprachen an sich, nicht von fertigen Bibliotheken, Werkzeugen etc.)
-
kartoffelsack schrieb:
Ein guter C++Programmierer kann in C++ wahrscheinlich 'bessere' (im Sinn von ausdrucksstärkere Formulierungen und allem was daraus in Sachen Wartbarkeit etc. erwächst) Programme schreiben als ein guter Java-Programmierer, weil ihm die Sprache mehr Möglichkeiten dafür lässt.
Nein. Java ist viel einfacher und deshalb auch besser wartbar.
-
kartoffelsack schrieb:
Das sqrt-Beispiel ist ein gutes Beispiel dafür, dass es - nur weil es eine 'objektorientierte' Sprache ist - nicht immer sinnvoll ist, alles objektorientiert zu machen (bzw. dass Java eben doch keine 100% oo-Sprache ist, sonst ginge ja 1.1.sqrt() )
Math.add()
ist _nicht_ objekt orientiert.ich sehe hier keine objekte.
Dazu braucht man aber halt mehr Erfahrung als in Java, wo es eben nur eine Möglichkeit gibt, die zwar nicht so perfekt passt aber im Endeffekt dasselbe erreicht.
es gibt genug andere moeglichkeiten. zB eben 2.sqrt() waere eine davon
aber worum es geht ist, dass Math.add() kein bisschen objekt orientiert ist. Es ist nichts anderes als ein kompliziertes int add(int, int);
und fuehrt dazu dass klassen in java oft nichts anderes sind als namespace ersatz.
ob das jetzt gut ist oder nicht, weill ich mal nicht bewerten. es geht eher mehr darum dass die leute verstehen muessen dass eine klasse erstmal rein garnichts mit OOP zu tun hat. Und Java ist kein bisschen 100% OOP oder so... ich habe schon genug C programme in Java gesehen: klappt super, da Java C so aehnlich ist kann man da viel 1 zu 1 uebernehmen. Und nur weil es dann Foo.bar() heisst statt foo_bar() macht es das nicht OO
-
Shade Of Mine schrieb:
und fuehrt dazu dass klassen in java oft nichts anderes sind als namespace ersatz.
"oft"? Übertreib mal nicht. Das betrifft vielleicht 2% aller Klassen, die man in einem Projekt hat.
-
Gregor schrieb:
Shade Of Mine schrieb:
und fuehrt dazu dass klassen in java oft nichts anderes sind als namespace ersatz.
"oft"? Übertreib mal nicht. Das betrifft vielleicht 2% aller Klassen, die man in einem Projekt hat.
dann halt manchmal. egal. tut eigentlich nicht viel zur sache.
auch wenn ich denke dass man eben viele dieser globalen funktionen dann halt einfach in die klasse packt wo man sie braucht und so wirkt es nicht so viel. und die macht man dann auch nicht static, und schon ists OO :p ok, das ist wohl nur bei schlechten programmierern der fall.
ich denke aber dennoch das java oft ein falsches gefuehl fuer anfaenger vermittelt. naemlich dass alles was in einer klasse ist, objekt orientiert ist. komplett unabhaengig davon was ein guter programmierer macht.
java vertritt dieses "pure OO" und C++ ist eben nicht "pure OO". Dabei hat man im endeffekt doch aehnliche ansaetze wie man manches loest. zB math.sqrt ist nichts anderes als std::sqrt. Kein bisschen OO der ansatz, aber halt praktisch. wobei c++ eben namespaces als konzept bietet und diese sind was namespace funktionalitaet betrifft den java klassen ueberlegen (ich kann jederzeit einem namespace ne funktion hinzufuegen). aber darum soll es hier ja nicht gehen: sondern darum dass es, egal wie man es dreht und wendet: Math ist ein namespace und sqrt eine globale funktion.
-
Shade Of Mine schrieb:
wobei c++ eben namespaces als konzept bietet und diese sind was namespace funktionalitaet betrifft den java klassen ueberlegen (ich kann jederzeit einem namespace ne funktion hinzufuegen).
Och, das kann man auch anders sehen. In C++ können Elemente eines Namespaces überall zu finden sein. In Java hat man durch den Namen der Klasse (und des Packages) gleich den genauen Ort der entsprechenden Datei gegeben. Ist also übersichtlicher, wartbarer.
...das ist ja auch eigentlich DER negative Aspekt, wenn man über globale Funktionen redet. Man sieht nicht gerade auf den ersten Blick, welche es gibt und wo sie sind. Das führt dann natürlich zu einer geringeren Wartbarkeit, zu einer geringeren Produktivität usw.. Dieser negative Aspekt wird durch die Namespaces in C++ nur teilweise aufgehoben. In Java hat man das mit statischen Funktionen in Klassen komplett erschlagen. ...das einzige, was da schlecht ist, sind die statischen Imports, die es jetzt neu gibt. Keine Ahnung, warum die eingeführt wurden: Ich habe sie noch kein einziges mal genutzt und halte sie auch für ein schlechtes Feature. ...und das sehen viele Leute so, die sich mit Java beschäftigen.
-
beispiel:
a=Math.sqrt(a);
sieht ok aus, oder?
Problem: a ist vom Typ MyInteger.ich definiere durch gewisse funktionen eben ein interface. zB dass ich die quadratwurzel aus einer zahl mit hilfe von sqrt ziehen kann. dazu muss ich aber in der lage sein sqrt fuer meine typen zu spezialisieren.
deshalb finde ich namespaces schoener als klassen - weil sie naemlich erweiterbar sind.
aber ich glaube wir schwenken vom thema ab
[edit]
omfg, ich hab den spamschutz aktiviert
[/edit]
-
Shade Of Mine schrieb:
ich definiere durch gewisse funktionen eben ein interface. zB dass ich die quadratwurzel aus einer zahl mit hilfe von sqrt ziehen kann. dazu muss ich aber in der lage sein sqrt fuer meine typen zu spezialisieren.
deshalb finde ich namespaces schoener als klassen - weil sie naemlich erweiterbar sind.
Ach so... dann erweiterst Du bei Dir also den Namespace std für Deine eigenen Projekte? Und andere Bibliotheken, die Du nutzt... machen die das auch? Ich bin der Meinung, dass wenn Du eigene Typen hast, für die Du eine schon vorhandene Funktion überladen musst, Du auch einen eigenen "Namespace" dafür machen solltest. Wo kommt man denn da hin, wenn sich jeder seinen eigenen Namespace std "definiert". Ein Wartungsalptraum. Wenn ein anderer Deinen Code liest, wird er ganz schön lange nach der Definition dieser Funktionen suchen. ...oder bezog sich das nur auf Deine eigenen "Namespaces"? ...naja, da kannst Du Deine Erweiterungen ja eh problemlos da unterbringen, wo sie hingehören und bist nicht auf die Erweiterungsfähigkeit des Namespaces angewiesen.
-
Gregor schrieb:
Ach so... dann erweiterst Du bei Dir also den Namespace std für Deine eigenen Projekte? Und andere Bibliotheken, die Du nutzt... machen die das auch?
dann interpretiert er std::sqrt so, daß dies der name für's radizieren ist. und den darf er natürlich bei völliger bedeutungsbeibehaltung duch zuatzimplemetierung erweitern. man darf ja auch dort lebende templates spezialisieren oder von dort lebenden klassen erben.
Ich bin der Meinung, dass wenn Du eigene Typen hast, für die Du eine schon vorhandene Funktion überladen musst, Du auch einen eigenen "Namespace" dafür machen solltest.
warum?
Wo kommt man denn da hin, wenn sich jeder seinen eigenen Namespace std "definiert". Ein Wartungsalptraum. Wenn ein anderer Deinen Code liest, wird er ganz schön lange nach der Definition dieser Funktionen suchen.
ja. rechtsklick auf den funktionsnamen und aussuchen des kontextmenupunks "go to definition". ewig lange zwei sekunden später hat er sie. welche geschwindigkeiten bist du mit eclipse so gewohnt, daß du 2 sekunden (inklusive zweimal klicken) für ganz schön lang halten tust?
-
volkard hat das meiste schon gesagt, aber ich will noch etwas hinzufuegen:
natuerlich fuege ich nicht nach belieben funktionen in std hinzu. Das waere natuerlich bloedsinn.
Aber man muss das jetzt etwas aus einem objekt orientierten aspekt sehen: ich stelle ein interface fuer bestimmte operationen zur verfuegung: zB habe ich sqrt, copy, ...
sqrt zB ist nichts anderes als eine operation auf einem numerischen objekt. ob das objekt jetzt ein int, double oder MyInteger ist, ist dem interface dabei egal.
Wenn ich nun eine klasse MyInteger habe, dann wuerde ich gerne diese Klasse sich wie ein int verhalten lassen. Ich will also quasi das Math-Interface implementieren. Deshalb spezialisiere ich (oder ueberlade - schiess mich tot, keine ahnung was von beiden ich da am besten mache (zuviel java in letzter zeit ;))) sqrt fuer MyInteger.
Oder eben copy, find, etc. fuer container - wenn ich einen eigenen container geschrieben habe, will ich ja dass er auch dieses interface implementiert.
das mache ich natuerlich nicht dauernd und es waere falsch zu sagen man braucht dieses feature, denn von einem technologischem standpunkt aus tut es ein a.sqrt() genauso - aber es sind eben diese features die den code schoener gestalten.
-
volkard schrieb:
Ich bin der Meinung, dass wenn Du eigene Typen hast, für die Du eine schon vorhandene Funktion überladen musst, Du auch einen eigenen "Namespace" dafür machen solltest.
warum?
Hab ich doch gesagt: Ich halte das nicht für besonders wartbar. Abgesehen davon könnte - sogar bei C++ - die Standardbibliothek auf lange Sicht offiziell erweitert werden. Dann kommt vielleicht eine Funktion mit gleicher Signatur in std rein, weil es sich gezeigt hat, dass sich eben jeder so eine Funktion selbst schreibt, weil sie gebarucht wird. Ok... dann gibt es also 2 Funktionen mit gleicher Signatur. Löscht Du dann Deine Funktion? Dann hat die Funktion aus dem offiziellen std aber vielleicht eine ganz leicht andere Semantik und plötzlich funktioniert Dein Code nicht mehr, ist also buggy. (um mal ein Negativ-Beispiel für eine entsprechende Erweiterung zu konstruieren) ...ok, bei EIGENEN Typen, die irgendwo in der Signatur auftauchen, ist das natürlich äußerst unwahrscheinlich. Aber es geht ja generell um die Erweiterungsfähigkeit des Namespaces.
Ich bin halt der Meinung, dass std vom Standard her vorgegeben ist. Wenn man da etwas reinbringen will, soll man bei der Standardisierung mitarbeiten. Das ist kein Bereich, den man eigenmächtig anfassen sollte. ...und genau das Gleiche gilt für für jeden anderen Namespace einer externen Bibliothek.
volkard schrieb:
Wo kommt man denn da hin, wenn sich jeder seinen eigenen Namespace std "definiert". Ein Wartungsalptraum. Wenn ein anderer Deinen Code liest, wird er ganz schön lange nach der Definition dieser Funktionen suchen.
ja. rechtsklick auf den funktionsnamen und aussuchen des kontextmenupunks "go to definition". ewig lange zwei sekunden später hat er sie. welche geschwindigkeiten bist du mit eclypse so gewohnt, daß du 2 sekunden (inklusive zweimal klicken) für ganz schön lang halten tust?
Oh... ich habe noch nie die Zeit gemessen... aber wenn da irgendwo Math.sqrt in einem Javacode steht, dann sehe ich unabhängig von der genutzten IDE oder des genutzten Editors sofort, dass das sqrt aus der Standardbibliothek kommt. Setzen wir also mal 0,1 Sekunden an. ...Faktor 20 schneller und man ist noch nichtmal auf die IDE angewiesen.
Viel wichtiger halte ich allerdings, dass ich in keinster Weise von meinem Lesefluss gestört werde: Ich muss nicht zur Maus greifen, um zu erkennen, was dort Sache ist.
-
Ist Objektorientierung nicht genau der engegengesetzer Weg ?
Man definiert ein Interface, aber man erweitert das Interface doch nicht. Wenn du eine neue Funktion im Namespace std für deinen MyInteger definierst, dann erweiterst du das Interface von sqrt.
Der richtige Weg wäre einen Operator int() in deiner MyInteger-Klasse zu definieren ( oder eben float/double ). So das sqrt() diesen Operator aufrufen kann.
Wenn ich einen std:sqrt(myinteger) sehe, dann schau ich erstmal stundenlang in die STL-Doku wo denn so ein sqrt definiert ist.
Du erweiterts doch die Funktion std:sort() doch nicht um deine ShadeListe. Sondern du definierst in der Klasse ShadeListe das Interface iterator.
-
Gregor schrieb:
konstruieren) ...ok, bei EIGENEN Typen, die irgendwo in der Signatur auftauchen, ist das natürlich äußerst unwahrscheinlich. Aber es geht ja generell um die Erweiterungsfähigkeit des Namespaces.
nö. es geht ab jetzt um die erweiterung des std-namespaces für eigene typen.
Ich bin halt der Meinung, dass std vom Standard her vorgegeben ist.
(hier frage ich vorhin "warum" und du hast leer zurückgeantwortet. das vereinfache ich jetzt mal.)
quatsch.Viel wichtiger halte ich allerdings, dass ich in keinster Weise von meinem Lesefluss gestört werde: Ich muss nicht zur Maus greifen, um zu erkennen, was dort Sache ist.
ok, du weißt sofort, in welcher datei das steht. aber das istr fürchterlich egal, wo das steht. kannst immer hingehen.
mir ist wichtig, daß ich die bedeutung von std::sort kenne und wer std::sort überlädt, wird sich dran halten.
oder für ein einfacheres beispiel, nehmen wir mal std::swap.
natürlich biete ich std::swap auch für eigene typen an.
-
ok, du weißt sofort, in welcher datei das steht. aber das istr fürchterlich egal, wo das steht. kannst immer hingehen.
mir ist wichtig, daß ich die bedeutung von std::sort kenne und wer std::sort überlädt, wird sich dran halten.
oder für ein einfacheres beispiel, nehmen wir mal std::swap.
natürlich biete ich std::swap auch für eigene typen an.Ist das jetzt ein Scherz ? Für jeden Type den du hast erweiterst du die STL ?
Was ist wenn jetzt 2 (oder besser 10) Leute an einem Projekt arbeiten. Diese 2 erweitern also für jeden Type den sie haben die STL. Das Ergebniss kannste dir doch Vorstellen oder ?
Am Ende findet dann ein Kampf in einer Arena statt, wenn 2 Programmierer die STL für den gleichen Type erweitern. Naja das sorgt wenigestns für Aufregung und für sportliche Bewegung am Arbeitsplatzt.
-
DEvent schrieb:
Man definiert ein Interface, aber man erweitert das Interface doch nicht. Wenn du eine neue Funktion im Namespace std für deinen MyInteger definierst, dann erweiterst du das Interface von sqrt.
nein.
ein interface ist eine beschreibung der schnittstellen. Wenn wir jetzt sagen ein Objekt implementiert IMath wenn es sqrt() anbietet.
class MyInt : public IMath { public: virtual MyInt sqrt(); };
das wuerdest du vermutlich als OK einstufen, oder?
aber was ist
a.sqrt();
denn anderes als
sqrt(a);
?es ist das selbe, nur andere schreibweise.
In LISP macht man es zB immer so: man definiert eine funktion sqrt() und implementiert die dann fuer alle "Klassen" die es anbieten.
Der richtige Weg wäre einen Operator int() in deiner MyInteger-Klasse zu definieren ( oder eben float/double ). So das sqrt() diesen Operator aufrufen kann.
ne, bloss nicht.
Wenn ich einen std:sqrt(myinteger) sehe, dann schau ich erstmal stundenlang in die STL-Doku wo denn so ein sqrt definiert ist.
wieso?
sqrt ist doch perfekt dokumentiert: du schaust in die doku und da steht
int sqrt(int); //ermittelt die quadratwurzel einer zahl und returned dieseund dann muss ich nicht nachsehen ob das fuer double anders ist. weil es fuer double definitionsgemaess genau gleich ist.
oder vielleicht steht da sogar nur
template<typename T>
T sqrt(T);da das waere ja nice, oder? reine interface definiton
Du erweiterts doch die Funktion std:sort() doch nicht um deine ShadeListe. Sondern du definierst in der Klasse ShadeListe das Interface iterator.
und da ein sort leider ewig dauern wuerde, ich aber mit ein paar tricks das sortieren enorm schnell hinbekomme (weil ich ja die implementationsdetails meiner ShadeList kenne) baue ich mir eine spezialisierung fuer std::sort.
klar, es ist etwas "out of the box" denken noetig. aber OOP hat echt nichts mit Klassen zu tun. vergiss klassen. funktionen koennen genauso ein interface definieren.
-
DEvent schrieb:
Ist das jetzt ein Scherz ? Für jeden Type den du hast erweiterst du die STL ?
nein. wir spezialisieren.
wenn ich eine Klasse Bitmap habe die intern halt nen char* auf die daten haelt, dann kann ich natuerlich bei einem std::sort() auf ein array von bitmaps jedesmal n copy machen, oder aber std::swap spezialisieren.
dann spezialisiere ich std::swap so, dass er nur schnell die 2 pointer tauscht.
Ich habe die STL nicht erweitert, es ist keine funktionalitaet dazu gekommen.
ich haette genauso
class Bitmap : public ISwapable { public: virtual void swap(Bitmap&); };
machen koennen. nur dass es mit statischer polymorphie und std::swap einfach soviel besser ist.
Was ist wenn jetzt 2 (oder besser 10) Leute an einem Projekt arbeiten. Diese 2 erweitern also für jeden Type den sie haben die STL. Das Ergebniss kannste dir doch Vorstellen oder ?
ja. wunderbarer code.
Am Ende findet dann ein Kampf in einer Arena statt, wenn 2 Programmierer die STL für den gleichen Type erweitern. Naja das sorgt wenigestns für Aufregung und für sportliche Bewegung am Arbeitsplatzt.
wieso sollten sie das tun?
dann kannst du genauso sagen es macht keinen sinn klassen zu verwenden, weil ja jeder eine funktion draw() einbauen koennte und dann hast du 10 draw() funktionen...ne, ne, ne. soviel uebersicht muss das team schon haben dass sie jede schnittstelle einer klasse nur einmal implementieren.
std::swap ist nichts anderes als eine implementierung des interfaces ISwapable. die std::swap spezialisierung findet sich auch direkt in der datei mit der interface definition der klasse. also da kann man nix doppelt implementieren...
PS:
es wir keine neue funktion hinzugefuegt. der std namespace bekommt nicht mehr funktionalitaet. es kommt nichts neues dazu.ich implementiere lediglich ein interface. mehr nicht.
nur dass das interface halt statisch ist und nicht dynamisch. (statische polymorphie ist auch polymorphie ;))
-
A* a = new A;
ist auch nicht OO!
hier wird der KLASSE A die Nachricht "new" geschickt, ein Objekt A zu erstellen. Im OO-System schickt man jedoch Nachrichten an OBJEKTE. Allgemein passen statische Funktionen nicht in das OO-Paradigma... was nun?zu namespaces vs. static imports:
Klar, man hätte in java vielleicht Namespaces einführen können, da Math nicht wirklich eine schöne Klasse darstellt. Aber was ich in c++ doof finde, ist, dass ich bei Namespaces "::" und bei Objekten oder Klassen "." schreiben muss. In Java muss ich in der IDE "." schreiben, und schon listet mir die Code-Completion alles auf. In c++ muss ich vorher genau wissen, ob Math nun eine Klasse oder ein Namespace ist....