Code: Alles auswählen
Foo* foo = NULL;
void* vp = foo
foo = static_cast<Foo*>(vp); // correct
foo = reinterpret_cast<Foo*>(vp); // also correct
EDIT: Fixed topic, meinte natürlich reinterpret, nicht dynamic
Code: Alles auswählen
Foo* foo = NULL;
void* vp = foo
foo = static_cast<Foo*>(vp); // correct
foo = reinterpret_cast<Foo*>(vp); // also correct
Afaik gibt es da keinen Unterschied. Aber das gilt wirklich nur für void * (und vielleicht für den artverwandten char *; habe die Paragraphen nicht griffbereit).kaiserludi hat geschrieben:Ist einer der beiden Casts aus irgendeinem Grund zu bevorzugen oder ist es reine Geschmackssache, welchen von den beiden man in dem Fall statt dem ebenfalls möglichen C-Cast nimmst?
Krishty hat geschrieben:(dynamic_cast verhält sich wie static_cast, nur, dass es durch die Funktionstabellen und Typinformationen sicherstellt, dass die Konvertierung gültig ist. Dadurch steigt aber übrigens auch seine Laufzeit von O(1) auf O(Vererbungstiefe zwischen den Klassen).)
Das ist übrigens auch wieder ein argument dafür, sein vererbungshierarchien flach zu halten, und lieber vieles durch komposition/delegation zu machen, statt durch vererbung. (ich meinte, ich hätte letztens hier so eine diskussion gelesen, wo es darum ging, ob man einen der std container nun besser wrapt oder von ihm erbt...)Krishty hat geschrieben:Polymorphie ist scheißkomplex
Sorry, ging mir um reinterpret_cast, nicht um dynamic_cast.FlorianB82 hat geschrieben:aus meinem bauchgefühl heraus würde ich immer den schwächstmöglichen cast verwenden, d.h. static_cast.
edit: gerade nochmal näher drüber nachgedacht, und festgestellt, dass dynamic_cast an der stelle auch nicht wirklich sinn macht. das hier scheint dem rechtzugeben: http://www.gamedev.net/topic/492353-c-d ... -and-void/
Der generelle Unterschied zwischen den beiden ist mir bekannt. Mir ist bloß gerade aufgefallen, dass ich bei void* keinen Unterschied feststellen konnte.Krishty hat geschrieben:Afaik gibt es da keinen Unterschied. Aber das gilt wirklich nur für void * (und vielleicht für den artverwandten char *; habe die Paragraphen nicht griffbereit).kaiserludi hat geschrieben:Ist einer der beiden Casts aus irgendeinem Grund zu bevorzugen oder ist es reine Geschmackssache, welchen von den beiden man in dem Fall statt dem ebenfalls möglichen C-Cast nimmst?
Falls du den Unterschied zwischen reinterpret_cast und static_cast wissen möchtest: reinterpret_cast gibt dieselbe Stelle im Speicher aus, die reingegeben wurde. Und das ist, auch, wenn es kontraintuitiv klingt, oft unerwünscht …
Ich würde das eher unterordnen bei der Frage, ob man einen Container nun wrappt oder von ihm erbt. Da gibt es genug andere Punkte, die für diese Entscheidung wichtiger sind (will man den Zugriff auf bestimmte API-Parts des Originals in seiner "Erweiterung" unterbinden, ist der Container überhaupt darauf ausgelegt, vererbt zu werden, etc. (z.B. kommt man bei Class Clustern gar nicht drumherum, entweder zu wrappen oder aber das Speichermanagment neu zu implementieren, das ist aber eher ein Problem, welcfhe in objC auftritt, wo Class Cluster dank Cocoa recht verbreitet sind), wenn man alles, was fürs wrappen spricht, verneinen kann und der Originalcontainer eine umfangreiche API hat, (welche man komplett übernehmen will), die sich womöglich auch noch ab und zu ändert, dann bietet es sich normalerweise eher an, zu erben, da man sich so einen Haufen Programmierarbeit gegenüber dem Wrappen spart).FlorianB82 hat geschrieben:Krishty hat geschrieben:(dynamic_cast verhält sich wie static_cast, nur, dass es durch die Funktionstabellen und Typinformationen sicherstellt, dass die Konvertierung gültig ist. Dadurch steigt aber übrigens auch seine Laufzeit von O(1) auf O(Vererbungstiefe zwischen den Klassen).)Das ist übrigens auch wieder ein argument dafür, sein vererbungshierarchien flach zu halten, und lieber vieles durch komposition/delegation zu machen, statt durch vererbung. (ich meinte, ich hätte letztens hier so eine diskussion gelesen, wo es darum ging, ob man einen der std container nun besser wrapt oder von ihm erbt...)Krishty hat geschrieben:Polymorphie ist scheißkomplex
Und für mich persönlich auch ein argument, multiple inheritance zu vermeiden.
Mir wärs lieber, die wären kürzer. So kommt man nur immer in Versuchung, nen c-cast zu nutzen, um sich nicht die Finger wund zu tippen, insbesondere, wenn man statt dem C-Cast gleich 2 C++ Castgs bräuchte.Krishty hat geschrieben: Das Standardkomitee hat den gefährlichen Casts extra die längsten Namen zugeordnet; reinterpret_cast ist wesentlich unangenehmer zu schreiben als static_cast. Da aber C-Casts die kürzeste Methode sind und bleiben, ist die ganze „man fühlt, wenn man was falsches macht“-Sache komplett für’n Popo.
ah, damn. ich hatte lustigerweise auch erst reinterpret_cast angenommen, aber dann beim zweiten lesen den dynamic_cast bemerkt...kaiserludi hat geschrieben:Sorry, ging mir um reinterpret_cast, nicht um dynamic_cast.
da hast du völlig recht. deswegen schrieb ich ja "auch" ein argument. dass es da noch viele andere gibt, die je nach situation verschieden stark wiegen, ist klar (man denke nur, man müsste std:string wrappen, viel spaß...).kaiserludi hat geschrieben:Ich würde das eher unterordnen bei der Frage, ob man einen Container nun wrappt oder von ihm erbt. Da gibt es genug andere Punkte, die für diese Entscheidung wichtiger sind
mir war dieses glück noch nicht beschert, aber da hast du vermutlich einfach größere/kompliziertere software vor dir als ich =).kaiserludi hat geschrieben:aber in Sprachen ohne sie habe ich die jeweilige Sprache deswegen schon oft genug verflucht und mir gewünscht, ich könnte für den Code C++ einsetzen, denn ab und zu hat man eben doch Situationen, in denen man viel tricksen und unintutive Umwege gehen muss, um an multipler Vererbung vorbei zu kommen
Beispiel, mit welchem ich dieses Jahr in objC schon viel Spaß hatte:FlorianB82 hat geschrieben:mir war dieses glück noch nicht beschert, aber da hast du vermutlich einfach größere/kompliziertere software vor dir als ich =).kaiserludi hat geschrieben:aber in Sprachen ohne sie habe ich die jeweilige Sprache deswegen schon oft genug verflucht und mir gewünscht, ich könnte für den Code C++ einsetzen, denn ab und zu hat man eben doch Situationen, in denen man viel tricksen und unintutive Umwege gehen muss, um an multipler Vererbung vorbei zu kommen
nun, wenn man dann wirklich das jeweilige komplette interface wrappen muss (und nicht nur ein kleiner teil ausreicht, meistens komme ich so dann ganz gut weg), dann würde ich wohl auch den weg der MI wählen. das erscheint da ja dann das einfachste.kaiserludi hat geschrieben:Beispiel, mit welchem ich dieses Jahr in objC schon viel Spaß hatte:
SomeContainer : Object; // gigantisch umfangreiche API
SomeMutableContainer : SomeContainer; // noch umfangreichere API als SomeContainer
SomeEnhancedFunctionalityContainer : SomeContainer; // noch umfangreichere API als SomeContainer
SomeMutableEnhancedFunctionalityContainer : SomeEnhancedFunctionalityContainer, SomeMutableContainer;
Nö, gibt keien Virtualität in objC. objC ist für den Compiler reines C, bzw. objC++ für den Compielr reines C++. Der obj-Part, also alles mit Smalltalk-Syntax, wird per Präprozessor in C bzw. C++ umgewandelt. Entsprechend ist dort auch nur das möglich, was man ohen Compile rein per Präprozessor umsetzen kann.FlorianB82 hat geschrieben:nun, wenn man dann wirklich das jeweilige komplette interface wrappen muss (und nicht nur ein kleiner teil ausreicht, meistens komme ich so dann ganz gut weg), dann würde ich wohl auch den weg der MI wählen. das erscheint da ja dann das einfachste.kaiserludi hat geschrieben:Beispiel, mit welchem ich dieses Jahr in objC schon viel Spaß hatte:
SomeContainer : Object; // gigantisch umfangreiche API
SomeMutableContainer : SomeContainer; // noch umfangreichere API als SomeContainer
SomeEnhancedFunctionalityContainer : SomeContainer; // noch umfangreichere API als SomeContainer
SomeMutableEnhancedFunctionalityContainer : SomeEnhancedFunctionalityContainer, SomeMutableContainer;
einfach bleibt das aber auch nur, wenn sich die interfaces bzw deren implementierung der beiden geschwisterklassen nicht im wege stehen; "Mutable" also möglichst orthogonal zu "EnhancedFunctionality" bleibt. anonsten wirds leicht furchtbar.
ich bin insgesamt halt einfach etwas vorsichtig mit vererbung; wie oft sieht man vererbungshierarchien, die so einfach falsch sind (sprich: dem LSP mal so gar nicht entsprechen), und die offensichtlich nur entstanden sind aus der denkweise: cool, so kann ich möglichst einfach und schnell meinen code wiederverwenden. dass vererbung nicht für code-wiederverwendung, sondern für polymorphie gut ist, wird oft übersehen. was dann raus kommt, ist fragwürdig. (und streng genommen hört sich das beispiel oben auch ersteinmal nach wiederverwendung an. klar könnte man das ganze dann auch polymorph verwenden, sofern die entsprechenden funktionen virtuell sind (gibt es das so in obj-c? davon habe ich keine ahnung...). wenn nicht (wie zum beispiel dei den containern der stl), dann ist das ganze zumindest theoretisch falsch.)