PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verräter und ihre Implementierung


del_4901
2006-05-13, 20:32:45
Ich hab vollgendes Problem in einem meiner Projekte habe ich alle meine classen von meiner abstrakten classe object abgeleitet. Wenn obj1 von obj2 daten braucht bzw. den state von obj2 ändern will. so schickt er einen Event in meinen händler macht dann irgendwas anderes oder legt sich schlafen. Der Handler legt dann fest wann obj2 die daten schickt bzw. den state ändert und benachrichtigt obj1 (z.B indem ob2, obj1 einen Event schickt ^^) Das Problem an der ganzen Sache ist nun das ich als Programmierer, ja manchmal dran interessiert bin was mein Objekt eigendlich ist. Handelt es sich hierbei um einen Baum/Warteschlange/Renderer/Apfel/Birne/WeißDerGeier? Ich brauch also Jemanden der mir Verrät was ich für ein objekt habe. Und das Möglichst so implementiert, das ich da nicht viel rumdocktorn muss wenn ich mir neue Klassen entwickel. Im mom ist das nicht schwer ich hab nur eine Handvoll von Typen/Klassen.

virtual enum Objecttyp object::getType(){return _Renderer;}

gibt mir den Typ und an den entsprechenden Stellen caste ich dann von Hand auf das objekt. Das ist aber irgendwann bestimmt sehr sehr unübersichtlich.

1. will ich diesen hässlichen _ wegbekommen
2. brauch ich irgendeinen VariablenTyp den ich zum casten verwenden kann
3. will ich diese enum Liste wegbekommen
4. muss ich bei der Erzeugung von objekten irgendwie rausbekommen was ich mir da eigendlich in erzeugt habe, und in einer variable in object speichern (nennen wir sie mal objtype)
5. objtype kann ich dann einfach über eine methode zurückgeben lassen
6. wenn ich den inhalt noch zum casten verwenden kann währ das optimal

7. ich würd das gern selber implementieren und nicht unbedingt auf fremde Klassen zurückgreifen.


Ich hab jetzt irgendwie nen Brett vorm Kopf, und mir fällt keine Implementierung ein, die ich hoffendlich in Zukunft nie wieder "anfassen" muss.


Ich hätte vllt noch sagen sollen, das es sich um C++ Native Code handelt ^^

Trap
2006-05-13, 21:59:26
Warum benutzt du nicht einfach die in C++ eingebaute runtime type information?

dynamic_cast macht wahrscheinlich das was du suchst.

Coda
2006-05-13, 22:00:43
Bzw. typeof()

del_4901
2006-05-13, 23:17:13
Omg!

bei dynamic_cast muss ich trotzdem noch den typ angeben ...
bei Managed Code vllt nicht mehr!


und typeof() ist so ein gcc dingens. und GetType()
gibs auch wieder nur bei ManagedCode

Coda
2006-05-13, 23:19:46
Ich meinte natürlich typeid(), sorry. Und ja, das ist offizielle C++-Spec.

del_4901
2006-05-13, 23:54:12
"laufzeit casten" ist nicht ... wie ich das so sehe ... währ eigendl. auch gar nicht mal so "unlogisch".

weil dynamic_cast ist auch nicht wirklich dynamisch .. ist schießlich auch blos ein template ... damit .... wieder an 3 Klassen rumschreiben um neue Funktionalität reinzubringen ... ich bin mit meinem semantischen konzept noch nicht wirklich zufrieden. Schoen ich kann mir jetzt mit der typeid den typen ausgeben lassen ... naja wenigstens verschwinden jetzt diese hässlichen _ und das enum ^^

del_4901
2006-05-13, 23:56:14
Coda[/POST]']Ich meinte natürlich typeid(), sorry. Und ja, das ist offizielle C++-Spec.

Ja über Letzteres findet man auch was, und hättest du eine sec später editiert ... hättest du dir noch meinen Flame anlesen können. ^^

Aber wie immer: "Hätte der Hund net geschissen, hätt er nen Hasen gehabt"

Coda
2006-05-13, 23:57:03
dynamic_cast ist kein Template.

Sieh mal, die C++-Designer sind keine ganz doofen Menschen und als sie das Thema RTTI einbauen mussten um zu verhindern dass jeder sein eigenes Inkompatibles System baut haben sie sich schon was dabei gedacht.

del_4901
2006-05-14, 00:25:53
Coda[/POST]']dynamic_cast ist kein Template.

Sieh mal, die C++-Designer sind keine ganz doofen Menschen und als sie das Thema RTTI einbauen mussten um zu verhindern dass jeder sein eigenes Inkompatibles System baut haben sie sich schon was dabei gedacht.

warum macht der compiler dann immer mecker wenn ihn mit ner typeid füttern will?

Mach am besten mal ein Beispiel, die Beispiele in der MSDN helfen mir nicht wirklich, oder ich steh heut einfach nur aufm Schlauch.

HellHorse
2006-05-14, 09:17:28
Was spricht gegen double dispatch oder sind objektorientierte Lösungen nicht willkommen?

Coda
2006-05-14, 10:19:57
AlphaTier[/POST]']warum macht der compiler dann immer mecker wenn ihn mit ner typeid füttern will?
Du must Runtime-Type-Informations in den Compileroptionen anschalten.

Trap
2006-05-14, 12:36:24
HellHorse[/POST]']Was spricht gegen double dispatch oder sind objektorientierte Lösungen nicht willkommen?
Die Fragestellung ist mir nicht so ganz klar, wenn man wissen will ob ein Objekt den Typ hat den man grade haben will, dann kann man das mit dynamic_cast machen.

Wenn man für viele verschiedene mögliche Typen unterschiedliche Bearbeitungsschritte anwenden will dann ist ein Visitor-Pattern/double-dispatch sauberer.

HellHorse
2006-05-14, 12:51:47
Trap[/POST]']Die Fragestellung ist mir nicht so ganz klar, wenn man wissen will ob ein Objekt den Typ hat den man grade haben will, dann kann man das mit dynamic_cast machen.

Wenn man für viele verschiedene mögliche Typen unterschiedliche Bearbeitungsschritte anwenden will dann ist ein Visitor-Pattern/double-dispatch sauberer.
Wenn man für alle Typen die gleichen Bearbeitungsschritte anwendet braucht man ja deren Typen nicht zu wissen. Oder sehe ich das falsch?

Trap
2006-05-14, 13:30:22
Mit meinem ersten Satz mein ich sowas wie:
obj* x = func();
apfel* y = dynamic_cast<apfel*>(x);
if(y)
//machwas mit y
else // ignorier es
Dafür benutzt man kein Visitor-Pattern.

HellHorse
2006-05-14, 16:20:35
Warum nicht einfach is_apple?

Coda
2006-05-14, 16:40:55
Hm? Sowas müsste man ja dann für jedes Objekt implementieren.

Obwohl:

#include <iostream>

class Apple
{
public:
virtual ~Apple() {}
};

class RedApple : public Apple
{
public:
virtual ~RedApple() {}
};

class Birne
{
public:
virtual ~Birne() {}
};

template<class is_type,class type> bool is(type *obj)
{
return dynamic_cast<is_type*>(obj);
}

int main()
{
Apple apfel;
Birne birne;
Apple *roter_apfel = new RedApple();

std::cout << is<Apple>(&apfel) << std::endl;
std::cout << is<Apple>(&birne) << std::endl;
std::cout << is<RedApple>(roter_apfel) << std::endl;

delete roter_apfel;
}
Aber ob das soviel leserlichter ist als der dynamic_cast?

del_4901
2006-05-14, 18:59:42
Meine Handler funktionen "platzen" mir und 80% davon ist irgendwelches rausfinden was ich jetzt eigendlich vor nen event habe und das casten auf den richtigen Typ. (Das objekt handelt seine events selbst) ... Ich musss mal schauen, ob es nicht vllt. cleverer währ das die Events sich selber handeln und demzufolge immer einen This zeiger vom zu handelnden Objekt bekommen .... aber dann muss ich dort auch erstmal rauskriegen was ich für ein objekt habe und casten, um dessen state zu ändern

es ist alles blöd, meine handler werden einfach zuuu lang und irgenwie wollte ich das drücken, so das es lesbar bleibt und funktionalität hinzugefügt erden kann ohne gleich 10 Zeilen im obj.Handler() schreiben zu müssen.

Im guardian ist es mir soweit gelungen das ich kaum noch was ändern muss. Da muss ich nur noch eine Handvoll critical sections stopfen. ^^

del_4901
2006-05-14, 19:05:29
Coda[/POST]']Du must Runtime-Type-Informations in den Compileroptionen anschalten.
ich dachte immer wenn abrakte Klassen funzen ist RTTI schon an.

del_4901
2006-05-14, 19:13:49
was ich nun zum dynamic cast rausgefunden habe ist vollgendes:

1. funzt nur mit Zeigern oder Referenzen
2. der unterschied zw. static_ bzw. cstyle cast ist das ein Laufzeitcheck durchgeführt wird ob mein cast sinvoll ist
3. im günstigsten fall gibt mir das teil 0 zurück im schlimmsten knallts mit ner type_cast exception

zu .3 die exception kann ich mir an der stelle gar nicht leisten!

zu .2 wenn ich aus (vllt Gewohnheit) eh schon alles "vernagle" wozu brauch ich dann bitteschoen den Laufzeitcheck?

das führt mich zu der einen Schlussflogerung:
also nichtmehr vernalgeln und drauf los casten bis es klappt ... super idee ... wenn die catches nicht so teuer währn

also mir ist im mom kein Beispiel eingefallen wo dieses Verhalten sinnvoll währ... Tut mir Leid aber ich kann mit dem dynamic_cast nichts anfangen ... vllt hab ich einfach nur nen Brett vorm kopp und mir fällt eine 3te Funktionsmöglichkeit nicht ein.

del_4901
2006-05-14, 19:15:33
HellHorse[/POST]']Wenn man für alle Typen die gleichen Bearbeitungsschritte anwendet braucht man ja deren Typen nicht zu wissen. Oder sehe ich das falsch?

das währ schoen ... sind aber nicht immer genau die gleichen, der Anfang ist meißtens gleich das Ende kann vieles machen.

vllt sollte ich mal Prolog und Epilog Programmierung wieder ausm Kopp kramen.

del_4901
2006-05-14, 19:21:46
HellHorse[/POST]']Was spricht gegen double dispatch oder sind objektorientierte Lösungen nicht willkommen?

ok, das könnte vllt auch ne Lösung sein ... warscheinl. die sauberste ... die mir am besten gefällt ^^

HellHorse
2006-05-14, 21:03:32
Coda[/POST]']Hm? Sowas müsste man ja dann für jedes Objekt implementieren.
Nö, einmal in der Rootklasse (return false) und einmal in der Apfelklasse (return ture).

Coda
2006-05-14, 21:42:43
Und genau das macht RTTI intern (bzw. etwas effizienter weil man direkt über die VTable geht).... Man kann das Rad auch 10x hässlich neu erfinden.

AlphaTier[/POST]']ich dachte immer wenn abrakte Klassen funzen ist RTTI schon an.
Nö, das kannst du zumindest bei Visual C++ ausschalten.

AlphaTier[/POST]']was ich nun zum dynamic cast rausgefunden habe ist vollgendes:

1. funzt nur mit Zeigern oder Referenzen
2. der unterschied zw. static_ bzw. cstyle cast ist das ein Laufzeitcheck durchgeführt wird ob mein cast sinvoll ist
3. im günstigsten fall gibt mir das teil 0 zurück im schlimmsten knallts mit ner type_cast exception

zu .3 die exception kann ich mir an der stelle gar nicht leisten!

zu .2 wenn ich aus (vllt Gewohnheit) eh schon alles "vernagle" wozu brauch ich dann bitteschoen den Laufzeitcheck?

das führt mich zu der einen Schlussflogerung:
also nichtmehr vernalgeln und drauf los casten bis es klappt ... super idee ... wenn die catches nicht so teuer währn

also mir ist im mom kein Beispiel eingefallen wo dieses Verhalten sinnvoll währ... Tut mir Leid aber ich kann mit dem dynamic_cast nichts anfangen ... vllt hab ich einfach nur nen Brett vorm kopp und mir fällt eine 3te Funktionsmöglichkeit nicht ein.
Wie gesagt gibts auch noch typeid().

Es ist außerdem sehr logisch, dass man dynamic_cast natürlich nur auf Pointer und Referenzen anwenden kann, ansonsten weißt du den Typ doch sowieso immer.

Vor allem das hier:
zu .2 wenn ich aus (vllt Gewohnheit) eh schon alles "vernagle" wozu brauch ich dann bitteschoen den Laufzeitcheck?
Ich glaube du weißt gar nicht wozu du RTTI überhaupt brauchst, nicht?

Das ist nur sinnvoll wenn du einen Pointer bzw Referenzen vom Typ der Basisklasse hast und feststellen willst welche abgeleitete Klasse du gerade in der Hand hälst. Ansonsten nicht.

del_4901
2006-05-14, 22:57:16
Coda , abstrake Klassen besitzen sowas:

virtual void tuwas() = 0;


Ich bin nicht komplett doof, ich weiß schon was RTTI ist und wozu ich abstrake klassen misbrauchen kann

Coda
2006-05-14, 22:59:06
Was ist dann dein Problem? Der Unterschied zw. static_cast und dynamic_cast dürfte dann doch wohl klar sein.

del_4901
2006-05-15, 00:09:38
Coda[/POST]']Was ist dann dein Problem? Der Unterschied zw. static_cast und dynamic_cast dürfte dann doch wohl klar sein.
der Unterschied schon, aber der sinvolle Einsatz ist mir noch nicht ganz klar. Ich glaube das die ganze Geschichte von dynamic_cast erst ab gewissen Mehrfachvererbungsstrukturen sinn macht. Und die versuche Ich wie sicherlich auch jeder andere gewissenhafte Programmierer zu meiden.

Coda
2006-05-15, 08:49:48
Du kannst per static_cast eine Basisklassen-Pointer nicht auf einen Pointer auf die abgeleitete Klasse casten. Das kannst du nur per C-Style-Cast und dann natürlich unsicher, weil du es nicht zur Laufzeit prüfst.

Wenn du eh schon sicherstellst dass du nur die richtigen Objekte übergibst brauchst du sowieso keine RTTI.

Gast
2006-05-15, 15:32:38
Ich verstehe das Problem nicht so ganz. Es gibt imo zwei Möglichkeiten:

a) Die Klasse selber bestimmt wie man mit ihr umgehen soll: Polymorphie oder Templates (oder beides)

b) mit Templatespezialisierung:
// alles ungetestet!
template<class Type>
void machWasMitMir(Type& object)
{
std::cout << "Allgemeine Behandlung" << std::endl;
}

template<>
void machWasMitMir<Apfel>(Apfel& object)
{
std::cout << "Spezielle Behandlung für einen Apfel" << std::endl;

}

Das mit der Spezialisierung hat den Nachteil dass du alle Klassen kennen musst die eine Sonderbehandlung benötigen. Falls nicht bekommen sie eben nur eine Standardbehandlung.