Aktuelle Zeit: 27.04.2024, 08:46

Alle Zeiten sind UTC + 1 Stunde




Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 
Autor Nachricht
BeitragVerfasst: 08.02.2010, 21:08 
Offline
Benutzeravatar

Registriert: 17.04.2007, 08:42
Beiträge: 460
Wohnort: Willich, NRW
Hi,

hab diesmal ein Problem zum Thema C++ itself. Man betrachte folgenden Codeausschnitt:

Code:
class Base
{
//...
};

class Derived1 : public Base
{
//...
void do1(void);
}

class Derived2: public Base
{
//....
void do2(void);
}

class Manager
{
private:
  vector<Base*> elements;
};


Ich wollte alle Objete in einem Array zusammenfassen. Das Problem an sich ist nun, dass ich da, die Zeiger ja auf die Basisklasse zeigen nicht auf die in den geerbten Klassen definierten Funktionen keinen Zugriff habe. Ich kann also nicht

Code:
elements[0]->do1();


schreiben, was ich aber gern gemacht hätte. Und nun wollt ich mit dem static_cast zu Leibe rücken.

Code:
Derived1* temp = static_cast<Derived1*>(elements[0]);


Sieht mehr als unsicher aus, und wird in der Referenz auch immer als schelcht definiert. Hat einer Erfahrungen beim erzwingen dieses casts oder gibts generell eine andere Möglichkeit z.B. dass ich die Klassen anders und besser strukturiere. Hatte mir schon vorgestellt alle Methoden die D1 und D2 haben trotzdem in die Basisklasse zu stopfen und dann einfach in der entsprechenden Unterklasse leer zu lassen. Scheint mir aber auch nicht als eine allzu sinnvolle Lösung.

Vielen Dank für alle Tipps ;)

_________________
Bild

Irrlicht - From Noob To Pro A Guideline

--

Sonstige Projekte, Blog : http://www.rpdev.net


Nach oben
 Profil  
 
BeitragVerfasst: 09.02.2010, 07:27 
Offline
Benutzeravatar

Registriert: 16.10.2007, 07:56
Beiträge: 229
Wohnort: Regensburg
Ich würde eine "getType" Methode zur Basisklasse hinzufügen, pure virtual, und dann in jeder Subklasse einen eindeutigen Wert zurückgeben. Dann kannst du die zur Laufzeit unterscheiden. So machts Irrlicht auch.

_________________
Bild


Nach oben
 Profil  
 
BeitragVerfasst: 09.02.2010, 13:52 
Offline

Registriert: 17.11.2007, 11:15
Beiträge: 19
Schon mal etwas von dynamic_cast gehört? Damit kann man zur Laufzeit feststellen, ob ein Objekt einen bestimmten Typ hat.

Code:
Derived2 *d2 = dynamic_cast<Derived2 *>(elements[0]);
if (d2) //dynamic_cast gibt 0 zurück, wenn der Cast nicht funktioniert
{
   d2->do2();
}


Nach oben
 Profil  
 
BeitragVerfasst: 09.02.2010, 14:41 
Offline
Benutzeravatar

Registriert: 17.04.2007, 08:42
Beiträge: 460
Wohnort: Willich, NRW
Danke für eure Antworten. Hat mir weitergeholfen!

_________________
Bild

Irrlicht - From Noob To Pro A Guideline

--

Sonstige Projekte, Blog : http://www.rpdev.net


Nach oben
 Profil  
 
BeitragVerfasst: 10.02.2010, 07:18 
Offline
Benutzeravatar

Registriert: 16.10.2007, 07:56
Beiträge: 229
Wohnort: Regensburg
Cool ... das mit dem dynamic cast ist mir neu. Muss ich mir merken.

_________________
Bild


Nach oben
 Profil  
 
BeitragVerfasst: 18.02.2010, 16:51 
Offline
Benutzeravatar

Registriert: 07.08.2008, 11:31
Beiträge: 104
Hallo

Der dynamic_cast arbeitet zur Laufzeit. Auch können fehlgeschlagene Konvertierungen zwischen verwandten Klassen (in diesem Fall ein Downcast) während der Laufzeit festgestellt werden. Ist der Pointer auf das konvertierte Objekt gleich 0, lag ein Fehler vor. Bei Referenzen wird eine Ausnahme geworfen. Ist alles RTTI-Kram...

Aber zu sehr sollte man diese Techniken nicht ausreizen, denn ein gutes Design benötigt oftmals kein dynamic_cast oder nur an sehr wenigen Stellen. Zur Gewohnheit sollte man sich einen solchen cast demnach nicht machen.

Wenn Objekte innerhalb einer Liste o. Ä. gespeichert sind und der Reihe nach eine Methode der jeweiligen Basisklasse aufgerufen wird, muss das ganze natürlich auch irgendwo einen Zusammenhang oder Sinn erkennen lassen. In anderen Worten, Objekte/Klassen, die nicht zusammengehören, fasst man nicht zusammen. Die Frage ist WOZU benötige ich genau diesen cast. Würde das, was ich vorhabe, sich evtl. auch besser, elegenater lösen lassen? Was es in jedem Fall zu vermeiden gilt, ist ein Design, bei dem jedes oder fast jedes Modul Wissen über viele weitere Module besitzt. Also ein Design, bei dem jeder jeden kennt. Nicht, dass oberflächlich betrachtet alles schön organisiert und auf Ebenen verteilt wirkt (bei den Schnittstellen), intern aber (bei den Implementierungen) doch wieder mit casts gefuscht wird. Das bringt wenig. Die Abhängigkeiten zwischen den Modulen sollte man sich stets vergegenwärtigen und genau überprüfen.

Wie dem auch sein, ich denke, RTTI ist generell gesehen eher so etwas wie das letzte Mittel. Außerdem, wo es kritisch mit der Performance steht, sollte man so etwas ohnehin vermeiden.


Nach oben
 Profil  
 
BeitragVerfasst: 18.02.2010, 18:18 
Offline
Benutzeravatar

Registriert: 17.04.2007, 08:42
Beiträge: 460
Wohnort: Willich, NRW
Genau die Frage habe ich mir auch gestellt. Wie kann ich das Design so gestalten, dass in jener Domäne Wissen über etwaige Objekte vorliegt. Und ich denke da kann ich sogar noch was machen, da das aktuelle Design einiges an Redundanz auffährt und das kann ich nicht erlauben. Hab derweil mal etwas anderes versucht, von dem ich mir eigentlich die Lösung versprochen hatte, war aber dann n bissl enttäuscht darüber.

Ich habs derzeit über die Typisierung mittels einer enumeration gelöst, wie brainsaw mir es vorgeschlagen hat und werde mal das Klassendesign aber nochmal überdenken und evtl hier nochmal ein post schreiben, der euch nochmal zum denken anregen könnte *.*

danke für eure antworten bis hier her

mfg heck

_________________
Bild

Irrlicht - From Noob To Pro A Guideline

--

Sonstige Projekte, Blog : http://www.rpdev.net


Nach oben
 Profil  
 
BeitragVerfasst: 18.02.2010, 19:29 
Offline
Benutzeravatar

Registriert: 07.08.2008, 11:31
Beiträge: 104
Zitat:
Hab derweil mal etwas anderes versucht, von dem ich mir eigentlich die Lösung versprochen hatte, war aber dann n bissl enttäuscht darüber.
Was denn? :)

Die Sache mit der Enumeration ist natürlich auch eine Lösung, nur besteht hier das Problem der Inflexibilität. Fügst du eine neue Klasse hinzu, musst du jedes Mal deine Enumeration korrigieren, bzw. ergänzen. Dein Set an Klassen ist somit "irgendwo" fest definiert. Ich meine, eine Enumeration zu bearbeiten ist technisch gesehen wohl kein Hindernis, nur irgendwie bekommt man mit der Zeit das schleichende Gefühl irgendwie ist das doch alles (...) ihr wisst schon was ich meine. Das ist jedoch alles von Situation zu Situation unterschiedlich. Besitzen Klassen zwei oder mehrere Aufgaben in einem System (mal rein theoretisch, ob das nun gut oder nötig ist, sei mal dahingestellt), dann kann man immer noch von zwei oder mehreren Schnittstellen erben. Das ist aber glaube ich nicht ganz das, worum es hier eigentlich geht.

Ein Beispiel:
Angenommen ich besitze eine Liste aller Objekte einer Spielwelt. D. h. alle Charaktere, Tiere, Häuser, Wände, eben alles. Alle diese Welt-Objekte besitzen eine gemeinsame Basisklasse. Die Liste speichert Zeiger zu den jeweiligen Basisklassen. Beispielsweise haben wir sowas wie std::vector<WorldObject*>, oder man bezeichne die Objekte als Nodes, vorliegen. Es stellt sich hier nun die Frage, was alles kann und soll ich nun mit dieser Liste anfangen, bzw. welche Operationen können/sollten ausgeführt werden? Die konkreten Klassen kenne ich jedenfalls nicht. Die Basisklasse bietet vermutlich nur wenige Funktionalitäten, allerhöhst ein paar ganz allgemeine polymorphe Update-Methoden und Positionierungs-Kram. Was unternehmen wir aber, wenn wir nur ganz spezielle Update-Funktionen aller Charaktere aufrufen möchten? Alle Objekte in der Liste auf den gewünschten Typ hin zu testen wäre ziemlich blöd. Zwar relativ einfach und durchaus realisierbar, aber eben nicht das Wahre. Es gibt zahlreiche Alternativen, angenommen wir wollen den Charakter-Zustand der Figuren aktualisieren. Dann könnten wir dieses Verhalten als eigene AI-spezifische Klasse auslagern, darauf in der Charakter-Klasse verweisen und zugreifen. Ein Charakter besitzt ein Verhalten. Wir führen auch eine Liste aller Verhalten (unsere "Seelen" der Figuren), welche regelmäßig aktualisiert werden. Oder so etwas in dieser Richtung eben. Man sollte eben alles ein wenig dezentralisieren. Das System wird zunächst ein wenig komplizierter, am Ende aber dann doch besser funktionieren. Ich meine, was hat eine Welt-Objekt-Liste überhaupt mit der Aktualisierung der Verhaltens(muster/objekte) von Charaketeren zu tun? Also würde hier schon mal etwas mit den Verantwortlichkeiten der Module nicht stimmen oder man sollte versuchen auf eine passendere Art (von einem anderen Ort aus?) auf die gewünschten Objekte zuzugreifen. (...)


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de