C++11 (aka C++0x) - Approval of Final Committee Draft
-
Ben04 schrieb:
krümelkacker schrieb:
Es ist doch eigentlich Deine Aufgabe, überzeugende Beispiele zu suchen und nicht meine.
Wie bitte? Ich muss rein gar nichts. Du bist derjenige der die erste Frage gestellt hat.
Ich bin derjenige, der wissen wollte, was an Deiner Variation von variadischen Templates besser/toll/eleganter sein soll. Das erschließt sich mir nicht automatisch. Ich weiß nicht einmal wie Du das genau gemeint hast. Und das liegt sicherlich nicht allein an mir. Ein "X ist doof, Y ist besser" ist ohne Begründung irgendwie wertlos, findest Du nicht? Habe ich da etwas übersehen?
<nochmal-nachguck>
Nein. Ich habe nichts übersehen. Alles, was Du dazu gesagt hast, war
Warum nicht einfach
template<class T> void f(T...t){ // T ist ein std::tuple und t eine Instanz davon }
und std::tuple dann direkt in den Compiler einbauen.
Das wars. Nur halb erklärt, was das bedeuten könnte, und keine weiteren Argumente oder Beispiele. Wie soll ein Aufruf aussehen? Wo wird das Tuple erzeugt? Muss ich das manuell machen? Soll es automatisch passieren? Wenn ja, wo? Beim Aufrufer oder innerhalb der Funktion? Welchen Typ hat denn eine bestimmte Instanz des Funktions-Temlates?
void(int,double)
odervoid(tuple<int,double>)
? Falls letzteres, würd ich behaupten, dass es eine schlechte Idee wäre. Es wären dann ja nicht wirklich variadische Funktionen sondern lediglich Syntax-Zucker bei dem Tuples auf der Aufruferseite automatisch erzeugt werden. Zeig mal ein Beispiel mit "perfect forwarding". Und warum will man das jetzt nochmal so schreiben? wo sind denn die Vorteile?Sorry, ohne weitere Erklärungen sieht das eher nach einem Gedankenfurz eines Großmauls aus. Ich habe schon den Eindruck, dass Du Dich mit C++ auskennst. Das impliziert aber keine guten Kommunikations-Skills. Du magst Dir ja dabei was gedacht haben ... aber davon ist leider nichts angekommen.
-
Ben04, es ist ziemlich traurig, was du hier abziehst. Old McDonald, krümelkacker und ich haben uns Mühe gegeben, sich Argumente zu überlegen und eine sinnvolle Diskussion zustande zu bringen. Dann kommst du und tust so, als wären wir Vollidioten, mit denen so eine Diskussion reine Zeitverschwendung wäre. Selbst bist du natürlich der grosse Macker. Sehr guter Diskussionsstil, wirklich.
Falls du wieder bereit bist, eine normale Konversation zu führen, sag das. Dann erkläre ich auch, was ich mit meinen Punkten meinte und wieso es tatsächlich nicht so einfach ist. Aber auf sowas hier hab ich echt keine Lust.
-
krümelkacker schrieb:
Das wars. Nur halb erklärt, was das bedeuten könnte, und keine weiteren Argumente oder Beispiele. Wie soll ein Aufruf aussehen?
Das tuple-Interface ist doch klar, oder? In C++98 lässt sich das nicht definieren, also muss die tuple-Klasse halt direkt in den Compiler gebaut werden.
Dann macht der Compiler aus:
printf("...", a, b+1, move(c));
kurz
printf("...", make_tuple<int&, const int&, int&&>(a, b, c));
und man ist fertig. Die Vorteile sind, dass du mit dem Tupleparameter alles machen kannst was man mit Tuplen machen kann. Zum Beispiel kann man ein Objekt auch hinten abpellen anstatt immer nur vorne. Du kannst die Tuple-Objekte kopieren und zwischen speichern. Natürlich geht das auch mit Argumentpacks, diese sind ja schließlich von der Natur her genau das selbe und beide lassen sich ineinander überführen. Syntaktisch sind sie aber so verschieden, dass man die Tuple-Helferfunktionen nicht drauf anwenden kann. Warum also beides zweimal reinpacken? Das führt dazu, dass ich die Helferfunktionen zweimal schreiben muss oder ständlich ein make_tuple(blub...) mache. Ich hoffe ich brauche nicht erklären warum es schlecht ist ein und das selbe Feature (Tuples und Argumentpacks) zweimal mit unterschiedlichem Syntax zu haben.
[EDIT]Noch eine Sache die mit Tupel einfach ist aber mit Argumentpacks sehr schwer: Die Anzahl der Elemente soll ein perfektes Quadrat sein. Das "braucht" man zum Beispiel bei quadratischen Matrizen. Bei tuples liegt die Information über die Anzahl der Parameter als constexpr vor und kann direkt überprüft werden. Bei Argumentpacks muss ich mir die erst zusammenbauen (geht natürlich auch).[/EDIT]
krümelkacker schrieb:
Welchen Typ hat denn eine bestimmte Instanz des Funktions-Temlates?
void(int,double)
odervoid(tuple<int,double>)
? Falls letzteres, würd ich behaupten, dass es eine schlechte Idee wäre. Es wären dann ja nicht wirklich variadische Funktionen sondern lediglich Syntax-Zucker bei dem Tuples auf der Aufruferseite automatisch erzeugt werden.Siehst du, dass du auch von selbst drauf kommst, wenn du es nur versuchst. Wenn du noch mal nachdenkst, dann kommst du auch, darauf, dass variadische Templates nicht "variadischer" sind, sondern bis auf den Syntax genau das selbe machen.
Und jetzt mal ehrlich: Hast du bei der private-Geschichte überhaupt versucht ein Beispiel zu basteln, das die Kapselung bricht? Wenn nicht dann ist mein Gebashe gerechtfertigt.
-
Ben04 schrieb:
Die neuen variadischen Parameter gefallen mir auch nicht. Warum nicht einfach
template<class T> void f(T...t){ // T ist ein std::tuple und t eine Instanz davon }
und std::tuple dann direkt in den Compiler einbauen.
Frage:
Wie machst du dann sowas:template<typename> class function; template<typename R, typename ...ArgTs> class function<R(ArgTs...)> { // ... };
Auch wird zum Beispiel Boost.Spirit sicher ähnliches verwenden für die Regeln oder
std::bind
usw. Es geht hier nicht nur um eine variable Anzahl Parameter bei einer Funktion sondern auch Typen, welche durch eine variable Anzahl anderer Typen definiert werden. Nicht nurstd::tuple
macht davon Verwendung. Du unterschätzt hier eindeutig das Einsatzgebiet von Variadic Templates.Zu dem template&typename Kram, da stimme ich dir im Grossen und Ganzen zu. Es haben schon verschiedene Hersteller gezeigt, dass man es auch mit deutlich weniger umsetzen kann.
Bei
void*
ist es meiner Meinung nach eher eine subjektive Sache. Wenn ichvoid*
verwende, dann scheisse ich nicht auf die Typsicherheit, sondern hole diese meistens anderweitig nach. Ein kleinerstatic_cast
schadet da nicht und verhindert irgendwelche impliziten Unachtsamkeiten. Sicherlich nur ein sehr kleiner Schutz, aber mich stört dieserstatic_cast
wirklich nicht. Im Gegenteil, man könnte argumentieren, dass man damit den Leser darauf aufmerksam macht, dass man hier wieder in die normale Typsicherheit zurückwechselt. Der umgekehrte Fall ist schliesslich nicht so wichtig, da man mitvoid*
selber nichts anfangen kann.Grüssli
PS: Missverständnisse und andere Meinungen gibt es immer in Diskussionen. Deswegen ist der Diskussionpartner aber nicht gleich dumm und man muss ihn sicherlich nicht von oben herab behandeln.
-
Sieht doch schon besser aus.
Ben04 schrieb:
Und jetzt mal ehrlich: Hast du bei der private-Geschichte überhaupt versucht ein Beispiel zu basteln, das die Kapselung bricht? Wenn nicht dann ist mein Gebashe gerechtfertigt.
Ja. Wie stellst du sicher, dass der Anwender nicht in seinem Code Funktionen definiert, diese als privat bezeichnet und somit vollständigen Zugriff auf Klasseninterna erhält?
Der Entwickler der Klasse sollte eine Möglichkeit haben, zu bestimmen, wer welchen Zugriff erhält. Und dafür scheint mir die Klassendefinition am geeignetsten.
-
Nexus schrieb:
Wie stellst du sicher, dass der Anwender nicht in seinem Code Funktionen definiert, diese als privat bezeichnet und somit vollständigen Zugriff auf Klasseninterna erhält?
Da sie privat sind, kann er sie nicht aufrufen, also nutzt es ihm nichts.
-
Ben04 schrieb:
Hast du mal gelesen, was der schreibt? Ich zitiere mal:
Stroustrup schrieb:
Without it [= typename & template], syntax analysis of C++ would need to interact closely with semantic analysis – and would probably be impossible even in relatively simple cases.
Du redest hier darüber was der Programmier machen darf und Stroustrup redet über das was implementierbar ist. Das sind zwei völlig verschiedene Paar Schuhe.
Ich bezog mich mit dieser Zusammenfassung nur auf den Fall, warum man auch in Bereichen, in denen offensichtlich ein Typ vorliegen muss, man auch weiterhin
typename
verwenden muss.
Ich möchte nicht sagen, dass das die beste Lösung ist, aber es war wohl die einfachste (für das Standard-Kommittee).
Natürlich war der Hauptgrund das Parsen, aber dieser Grund war ja schon genannt worden.Ben04 schrieb:
Das ist Blödsinn und das hättest du selbst eingesehen, wenn du nur probiert hättest ein Beispiel zu finden.
Operatorüberladung kann zu lustigen Effekten führen.
Oder ist dir mal aufgefallen, dass folgendes gültig ist (kleines C-Überbleibsel)?struct X { struct A { char a[400]; }; struct B {}; static B A; };
Ich weiß, dass das unwahrscheinlich ist. Aber leider potenziell möglich.
Ben04 schrieb:
b) Wie wäre es wenn du auch wirklich das was ich geschrieben habe durch den Compiler jagen würdest?
Wenn du sagst,
T...
ist einstd::tuple<...>
(das heißt ein ganz normaler Typ), dann erwarte ich auch, dass ich das Argument nehmen kann, ohne dem Parameter einen Namen geben zu müssen. Das geht ja sonst auch in C++. Warum sollte es also nicht auch bei einemT...
gehen?
Bei Parameter packs kann man diese Mehrdeutigkeit auflösen, weil man ja noch die Deklaration als Template parameter pack in der Templatedeklaration hat, aber nicht bei deinem Vorschlag.Für Argumente gleichen Typs gibt es auch noch
std::initializer_list
, damit kann man auch etwas Ähnliches basteln wie eine Funktion mit einer geliebigen Anzahl Parametern. Sieht beim Aufruf aber nicht ganz so schön aus...Ben04 schrieb:
[EDIT]Noch eine Sache die mit Tupel einfach ist aber mit Argumentpacks sehr schwer: Die Anzahl der Elemente soll ein perfektes Quadrat sein. Das "braucht" man zum Beispiel bei quadratischen Matrizen. Bei tuples liegt die Information über die Anzahl der Parameter als constexpr vor und kann direkt überprüft werden. Bei Argumentpacks muss ich mir die erst zusammenbauen (geht natürlich auch).[/EDIT]
sizeof...(args)
wird es in C++0x geben.Wie würdest du dafür sorgen, dass man auf einfache Art und Weise auf alle Argumente eine Funktion anwenden kann? In C++0x gibt's ja bei diesen pack expansions die Möglichkeit, beliebige Ausdrücke auf alle Argumente anzuwenden.
Und wenn du Tupel verwenden willst, kannst du auch einfach
auto t = make_tuple(args...)
(vielleicht teilweise leicht angepasst) verwenden.
-
audacia schrieb:
Nexus schrieb:
Wie stellst du sicher, dass der Anwender nicht in seinem Code Funktionen definiert, diese als privat bezeichnet und somit vollständigen Zugriff auf Klasseninterna erhält?
Da sie privat sind, kann er sie nicht aufrufen, also nutzt es ihm nichts.
// MyClass.hpp class MyClass { public: void foo(char c) { fooPrivate(c); } // Ist sowas dann noch möglich? fooPrivate wäre nicht bekannt! }; // MyClass.cpp private void MyClass::fooPrivate(int val) { // ... } // EvilUser.cpp private void MyClass::fooPrivate(char c) { cout << "HrHrHr" << endl; }
-
Beispiel schrieb:
class MyClass { public: void foo(char c) { fooPrivate(c); } // Ist sowas dann noch möglich? fooPrivate wäre nicht bekannt!
Was im Header nicht bekannt ist, kannst du natürlich auch nicht referenzieren. Wie sollte der Compiler diese Funktion auch inline expandieren, wenn er fooPrivate() nicht kennt.
Mit Templates und einem Compiler, der "two-phase name lookup" nicht implementiert, kannst du allerdings eine eine derartige Situation konstruieren. Eine mögliche Gegenmaßnahme wäre, implizite Überladungen auf diesem Wege zu verbieten. Aber da wird dieses ach so einfache Feature natürlich schon wieder kompliziert.
-
Dein Ton lässt echt zu wünschen übrig, Ben04. Ich muss mir Deinen Überlegenheitskomplex nicht gefallen lassen.
... Ich hoffe ich brauche nicht erklären ...
Spar Dir die Mühe. Wir sind alle dumm und Du nicht, richtig?
Siehst du, dass du auch von selbst drauf kommst, wenn du es nur versuchst.
Ich habe mehrere Möglichkeiten aufgezählt, an die Du gedacht haben könntest. Welches davon richtig oder falsch ist, ergibt sich nicht aus deinem kurzen Einführungskommetar ("warum nicht so...").
[...] Wenn du noch mal nachdenkst, dann kommst du auch, darauf, dass [...]
[...] Und jetzt mal ehrlich: Hast du bei der private-Geschichte überhaupt versucht [...]
Nee, Dein Tuple-Ansatz überzeugt mich nicht. Und mit der Einstellung, mit der Du an diese "Diskussion" rangehst, kommst Du nicht weit. Was hast Du damit erreicht? Du hast es geschafft, dass ich kein Bock mehr habe, mit Dir noch ein Wort zu wechseln. Mission accomplished.
-
Dravere schrieb:
Frage:
Wie machst du dann sowas:template<typename> class function; template<typename R, typename ...ArgTs> class function<R(ArgTs...)> { // ... };
Auch wird zum Beispiel Boost.Spirit sicher ähnliches verwenden für die Regeln oder
std::bind
usw. Es geht hier nicht nur um eine variable Anzahl Parameter bei einer Funktion sondern auch Typen, welche durch eine variable Anzahl anderer Typen definiert werden. Nicht nurstd::tuple
macht davon Verwendung. Du unterschätzt hier eindeutig das Einsatzgebiet von Variadic Templates.Sehr guter Punkt. Das geht wohl nicht so wie ich mir das vorgestellt habe.
Wobei man sich durchaus überlegen könnte, ob man nicht allgemein eine Typlist als Tuple und damit als Typ ausfassen will. Damit wäre void(int, int, int) dann die selbe Signatur wie void(tuple<int, int, int>). Man müsste auch noch tuple<T> und T gleich setzen damit das funktioniert. Wahrscheinlich wird das aber wohl an irgendwelchen exotischen Konstrukten scheitern die man nicht brechen darf.
Die Essenz meines Arguments ist, dass wenn man Tuple hat nur noch unäre Funktionen braucht, da man damit alles zusammenbauen kann. C++0x muss an der Stelle also meiner Meinung nach unnötige Redundanz enthalten. Das ist nicht dramatisch, aber ich wäre nicht erstaunt, wenn man das vereinheitlichen könnte.
Dravere schrieb:
Sicherlich nur ein sehr kleiner Schutz, aber mich stört dieser
static_cast
wirklich nicht.Mich stört es jedes Mal wenn ich C-Code verbauen soll der malloc verwendet und jedes einzelne Mal frage ich mich was ich dadurch gewonnen habe. Durch manuelles rumfrickeln am Code damit der Compiler ihn frisst baue ich nämlich höchstens Fehler ein.
Die NULL-Problematik ist auch ein Kind von dieser Fehlentscheidung, da sich nullptr ohne Probleme mit den C-void* als Makro definieren ließ. Naja, hier kann man das Rad der Zeit wohl leider nicht mehr so einfach zurückdrehen auch wenn es mit Abstand die eleganteste Art wäre.
Dravere schrieb:
PS: Missverständnisse und andere Meinungen gibt es immer in Diskussionen. Deswegen ist der Diskussionpartner aber nicht gleich dumm und man muss ihn sicherlich nicht von oben herab behandeln.
Wenn dein Gegenüber aber die Ich-weiß-nicht-warum-aber-das-ist-nun-mal-so-also-hast-du-per-definition-unrecht-Keule auspackt, dann ist es in Internetforen die einzige mir bekannte Möglichkeit ein gewisses Fachniveau zu halten. Es gibt leider keinen zwingenden Grund einen Konsens zu finden und sich des wegen überhaupt mit den Argument des anderen zu beschäftigen.
Old McDonald schrieb:
Operatorüberladung kann zu lustigen Effekten führen.
Oder ist dir mal aufgefallen, dass folgendes gültig ist (kleines C-Überbleibsel)?struct X { struct A { char a[400]; }; struct B {}; static B A; };
Ich weiß, dass das unwahrscheinlich ist. Aber leider potenziell möglich.
Interessantes Beispiel. Bist du sicher, dass das auch in C++ gültig ist?
Ich kann mit Sicherheit sagen, dass zumindest einige MinGW-GCC Versionen damit nicht klar kommen. In der GDI+ gibt (gab) es irgendeinen Fall wo eine Instanz gleich hieß wie ihr Typ und das hat der MinGW zurückgewiesen. Der VC wird es wohl sicherlich schlucken. Die Details kenne ich nicht mehr, es liegt schon mehrere Jahre zurück.
Wahrscheinlich wäre es sinnvoll mal solche Konstrukte welche niemand verwendet zu depredecaten und eine Warnung vorzuschreiben. Sie sorgen nur für Ärger und nützen niemandem.
EDIT: Ich hab grad ein bischen mit dem Comeau-Compiler rumgespliet. Das ist scheinbar gültig und sieht so aus, als ob das implizite typedef struct A A; einfach fehlen würde. Dadurch ist X::A eindeutig die Instanz. typename T::A mit T=X ist nicht gültig und damit stellt es im konkreten Fall kein Problem dar.
In nicht Template-Code kannst du mit struct X::A dennoch eine Instanz anlegen. Ich habe es nicht geschafft das innerhalb eines Templates zu machen. struct typename und typename struct sind ungültig.
Old McDonald schrieb:
sizeof...(args)
wird es in C++0x geben.was neues gelernt, danke.
Old McDonald schrieb:
Und wenn du Tupel verwenden willst, kannst du auch einfach
auto t = make_tuple(args...)
(vielleicht teilweise leicht angepasst) verwenden.
Das meine ich mit leicht überführbar. Der andere Weg geht auch, auch wenn er syntaktisch schwerfälliger ist.
audacia schrieb:
Mit Templates und einem Compiler, der "two-phase name lookup" nicht implementiert, kannst du allerdings eine eine derartige Situation konstruieren. Eine mögliche Gegenmaßnahme wäre, implizite Überladungen auf diesem Wege zu verbieten. Aber da wird dieses ach so einfache Feature natürlich schon wieder kompliziert.
Stimmt, aber da bei Templates eh alles im Header stehen muss, bringt es aber eh nix außer Konsistenz.
Bei nicht template Code erlaubt das Konstrukt neue interne Funktionen einführen, ohne den Header zu verändern und damit einen Rebuild von allem Code auszulösen welcher diesen Header einbindet.
-
Ben04 schrieb:
...
Dann wäre es noch sinnvoll zu erlauben private Methoden außerhalb der Klasse zu deklarieren. Diese sind ein Implementierungsdetails welches nicht benötigt werden um die Größe eines Objekts zu berechnen. Es gibt also keinen Grund warum man sie in den Header packen müssen soll....Die Idee finde ich auch charmant.
Allerdings sehe ich da auch Einiges an "Verwirrungspotential":
1.) Wenn nicht wenigstens die Namen "reserviert" wären, könnten hässliche Namenskollisionen mit abgeleiteten Klassen auftreten (die nicht der Compiler erkennen kann).
2.) Dass private "Attribute" (die durchaus Einfluß auf die Objektgröße haben und genauso "Implementierungsdetail" sind) nicht ausgelagert werden können, empfinde ich als sehr unschön.
Spätestens bei Funktionsobjekten wirds da inkonsistent...Ob man das jetzt als "Grund, warum man sie in den Header packen muss" einstuft, weiß ich nicht - mir persönlich fällt nur keine andere Lösungsmöglichkeit ein.
BTW:
Beispiel schrieb:
...
// MyClass.hpp class MyClass { public: void foo(char c) { fooPrivate(c); } // Ist sowas dann noch möglich? fooPrivate wäre nicht bekannt! }; // MyClass.cpp private void MyClass::fooPrivate(int val) { // ... } // EvilUser.cpp private void MyClass::fooPrivate(char c) { cout << "HrHrHr" << endl; }
Das geht heute auch schon (natürlich mit Funktionsdekl. in der Klasse):
// MyClass.hpp class MyClass { public: void foo(char c) { fooPrivate(c); } private: void MyClass::fooPrivate(int val) }; // MyClass.cpp void MyClass::fooPrivate(int val){ } // EvilUser.cpp namespace { void evil(char c) { cout << "HrHrHr" << endl; } } void MyClass::fooPrivate(int c) // Ja - hier noch int { evil(c); }
Gruß,
Simon2.
P.S.: @Ben04: Ich mag ja leidenschaftliche Typen, aber überlege Dir doch mal in einer ruhigen Minute, wann der hohe Adrenalingehalt Deiner Beiträge die Ohren Anderer für Dein Anliegen wirklich weiter geöffnet hat ...
-
Simon2 schrieb:
1.) Wenn nicht wenigstens die Namen "reserviert" wären, könnten hässliche Namenskollisionen mit abgeleiteten Klassen auftreten (die nicht der Compiler erkennen kann).
Das Problem tritt aber auch jetzt schon auf, weil zuerst gekuckt wird worauf sich ein Identifier bezieht und dann erst wird der Zugriff geprüft. Du kannst also mit privaten Members globale ungewollt verdecken. Den privaten Teil einer Basisklasse zu verändern kann dazu führen, dass eine Abgeleitete bricht. Wenn du Namen aus der Klasse raus bewegst, dann verkleinerst du das aktuelle Problem sogar geringfügig.
-
Objective-C hat ein Feature namens category um uA das private Problem zu lösen. So wirklich toll ist das aber auch nicht. Ideal wäre es, wenn eine Klasse keine geschlossene Einheit ist, sondern man jederzeit neue Funktionen hinzufügen könnte...
Für das malloc problem kannst du einfach ein #define machen und malloc ein objekt returnen lassen dass sich implizit in alle zeiger typen konvertieren lässt. im idealfall lässt man natürlich den c code in einer .c datei, aber das geht ja leider nicht immer...
-
Shade Of Mine schrieb:
Ideal wäre es, wenn eine Klasse keine geschlossene Einheit ist, sondern man jederzeit neue Funktionen hinzufügen könnte...
So wie mit Extension Methods oder Class Helpers?
-
Shade Of Mine schrieb:
Objective-C hat ein Feature namens category um uA das private Problem zu lösen. So wirklich toll ist das aber auch nicht.
Können diese Erweiterungsfunktionen dann auch auf die Interna der Klasse zugreifen oder diese gar durch zum Beispiele neue Datenmember erweitern? Ich gehe mal davon aus, dass dies nicht möglich ist. Ich kenne mich mit Obj-C leider gar nicht aus und so aussagekräftig ist der Wikipedia Artikel leider nicht.
Shade Of Mine schrieb:
Ideal wäre es, wenn eine Klasse keine geschlossene Einheit ist, sondern man jederzeit neue Funktionen hinzufügen könnte...
Vielleicht. Mein Bauchgefühl tendiert da aber in eine andere Richtung. In C++ hast du die Möglichkeit freie Funktionen zu erstellen. Ich würde es für sinnvoller halten das Klasseninterface minimal zu halten und dann komplexere Funktionalität mit freien Funktionen aufzubauen.
-
Ben04 schrieb:
Können diese Erweiterungsfunktionen dann auch auf die Interna der Klasse zugreifen oder diese gar durch zum Beispiele neue Datenmember erweitern?
Datenmember muss ich zugeben, weiss ich nicht. Ich denke ja, würde aber meine Hand dafür nicht ins feuer legen. Eine category kann private daten haben, aber ob eine andere category dann darauf zugreifen kann - das weiss ich jetzt nicht.
zugriff auf private member hat eine category aber.
Vielleicht. Mein Bauchgefühl tendiert da aber in eine andere Richtung. In C++ hast du die Möglichkeit freie Funktionen zu erstellen. Ich würde es für sinnvoller halten das Klasseninterface minimal zu halten und dann komplexere Funktionalität mit freien Funktionen aufzubauen.
mir persönlich gefällt dieses "willkürliche" trennen zwischen member und freistehende funktion irgendwie nicht. natürlich ist die trennung nicht wirklich willkürlich, aber als anwender der klasse sind mir oft die design entscheidungen dahinter egal.
zB list::sort versus std::sort. natürlich macht es sinn dass eine list ein eigenes sort anbietet, aus einer technischen sicht, aber wenn ich das ding nur sortieren will, ist mir das eigentlich egal. wobei das jetzt von der signatur her ein dummes beispiel ist.
categories erlauben mir zB ähnlich dem prototype feature aus sprachen wie javascript, neue methoden zu einer bestehenden klasse hinzuzufügen und auch bestehende funktionen zu überschreiben. vl wäre es auch toll wenn o.f() und f(o) identisch wären... ich weiss nicht was mir da am besten gefallen würde. ich weiss nur, dass mir diese trennung member <-> freistehend nicht wirklich gefällt
@audacia:
ja, so etwas wie extension methods. class helpers kenne ich nicht.
-
Shade Of Mine schrieb:
zB list::sort versus std::sort. natürlich macht es sinn dass eine list ein eigenes sort anbietet, aus einer technischen sicht, aber wenn ich das ding nur sortieren will, ist mir das eigentlich egal. wobei das jetzt von der signatur her ein dummes beispiel ist.
Im Normalfall löst man so etwas über Spezialisierung/Überladung. Mir sind einige Fälle bekannt in denen das auch in der Praxis gut klappt.
Der Grund warum es in diesem konkreten Fall glaube ich nicht anders geht, ist dass du zum Sortieren das std::list Objekt selbst brauchst und dieses nicht aus den Iteratoren alleine bestimmen kannst.
Bei Klassenerweiterungen welche uneingeschränkt Zugriff auf die privaten Daten haben geht dir die Kapselung leider kaputt und ab einem gewissen Komplexitätsgrad deines Programms geht es einfach nicht mehr ohne. Das Problem ist halt, dass wenn du deine Klasseninterna änderst du Gefahr läufst, dass alle Erweiterungen zerbrechen.
Ob jetzt wirklich jede einzelne Klasse derart abgeschottet werden muss wie es C++ macht ist aber auch nicht klar. Mir gefällt das package Zugriffsrecht aus Java ganz gut. Das macht die Kapsel ein wenig größer, so dass eine handvoll Klassen rein passen aber nicht zu groß, als dass man Wartungsprobleme kriegen würde. Dadurch braucht man auch 90% der friends nicht mehr.
-
Mist.
Ich habs komplett verpasst.
http://www.hsr.ch/Agenda.6479.0.html?&uid=45&tx_nmagenda_pi_agenda_detail[view]=detail&cHash=640412452a@Dravere: Warst du da?
-
drakon schrieb:
@Dravere: Warst du da?
Habe angefragt und mitgeteilt bekommen, dass meine Anwesenheit unerwünscht wäre, daher bin ich nicht gegangen. Habe mich auch die ganze Woche aus Protest mit C# und Lua beschäftigt
Grüssli