Krishty hat geschrieben:Weil das Schreiben von Strings in Output-Streams weder ein Implementierungsdetail der String-Klasse ist, noch eins der Output-Stream-Klasse.
und weil der Operator nicht zwingend Zugriff auf irgendwelche private oder protected Variablen/Methoden einer der beiden Kalssen braucht, sondern wunderbar mit reinem Zugriff auf die public Interfaces der Klassen auskommt und natürlich, weil dank namespaces globale Funktionen nicht mehr das Risiko von Namenskollisionen erhöhen, sofern der Benutzer von der Unart absieht, alles und jeden mit "using namespace" einzubinden.
Habe irgendwo mal den interessanten Satz gelesen:
"Java- und C#-Programmierer werden verwundert sein, aber in C++ ist die objekorientierteste Art der Implementation einer Funktionlität keine Klassenmethode, sondern eine globale Funktion im gleichen Namespace wie die Klass, da sie so nciht mehr Zugriffsrechte bekomtm, als sie auch braucht."
Alles, was an privates rumpfuschen kann, ohne das tatsächlich zu müssen, erhöht nur das Risiko, dass der Wartungsaufwand sich erhöht, weil alles innerhalb der Klasse kreuz und quer auf Sachen zugreift, auf die es gar nicht zugreifen bräuchte. Alles, was nur übers öffentliche Itnerface drauf zugreift, muss nicht angefasst werden, sofern man nur an Implementierungsdetails was dreht und wenn man es doch umbauen muss, dann weiß man auch sofort, dass man anscheinend versehentlich doch das Interface verändert hat (z.B. durch Seitenwirkungen (um in der Diskussion Seiteneffekte/Nebeneffekte/Nebenwirkungen keinen zu bevorzugen ;) ) ).
Hat aber auch Vorteile, alles als Membermethoden von Klassen zu implementieren: So ist das ganze Interface eienr Klasse auch im Header in dieser zu finden und liegt nicht sonst wo verstreut in deinem potentiell rieisigen Namespace rum. Gerade wenn eine Methode oder ein Operator aber genauso gut zu einer anderen Kalsse gehören könnte, man es verstärkt Sinn, darüber nach zu denken, ihn/sie als gloable(n) Operator/Funktion in dem Namespace einzubauen.
Das erklärt dann auch, wieso es bei primitiven Datentypen wie intoder float anders gelöst ist:
Hier stellt sich die Frage nicht, in welcher von beiden Kalssen man es implementiert, in dem primitiven Typ geht nun mal schlecht, ohne, dass man eine Wrapperklasse drumherum aufbaut, die dann aus Performancegründen nicht überall genutzt wird.
Inkonsistent ist das trotzdem irgendwie.