 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
André Schmidt Guest
|
Posted: Sat Feb 05, 2005 11:15 am Post subject: designfrage |
|
|
Hallo!
Bastel an einem Weltraumspiel und habe zwei Grundklassen:
CTdObject - repräsentiert die darstellung eines Objekts
CSystemItem - beschreibt statische Einheiten eines Sonnensystems zB.
Sonne, Planeten etc.
CTdShip public CTdObject - stellt zB. Raumschiffe dar
CTdPlanet public CTdObject - stellt Planeten dar
Ich suche nun einen weg die Td-Objekte mit CSystemItems zu verbinden.
Logischerweise sollen nur zB CTdPlanet eine Verbindung zu einem
CSystemItems haben nicht aber CTdShip.
Soweit so gut - ich könnte nun einfach eine Klasse
CTdSystemItem : public CTdObject
bilden die den verweis auf das passende SystemItem enthält.
Jetzt kommt das Problem:
Es gibt eine Klasse CTdStation welche eine Orbitalstation repräsentiert
die sowohl ein CTdShip (3D-Modell) als auch ein CTdSystemItem (verweis
auf ein CSystemItem) ist.
Das hiesse aber
CTdStation : public CTdShip, public CTdSystemItem
was wenn ich richtig informiert bin nicht geht weil beide von CTdObject
abgeleitet sind.
nochmal kurz zur verständlichkeit die klassen mit ein paar
beispielattributen:
class CSystemItem
{
vector<CSystemItem*> m_aChilds;
CSystemItem *m_pParent;
float m_fSunDist, m_fParentDist, m_fRadius; // etc.
CTdSystemItem *pTdItem;
};
class CTdObject
{
D3DXVECTOR4 m_vLoc;
D3DXMATRIX m_matDir;
virtual void Render();
};
class CTdSystemItem : public CTdObject
{
CSystemItem *m_pSysItem;
virtual void Render();
};
class CTdPlanet : public CTdSystemItem
{
virtual void Render();
}
class CTdShip : public CTdObject
{
CD3DMesh *m_pMesh;
virtual void Render();
}
class CTdStation : public CTdShip, public CTdSystemItem // ???
{
virtual void Render();
}
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sat Feb 05, 2005 3:46 pm Post subject: Re: designfrage |
|
|
André Schmidt wrote:
| Quote: | CTdShip public CTdObject - stellt zB. Raumschiffe dar
CTdPlanet public CTdObject - stellt Planeten dar
Ich suche nun einen weg die Td-Objekte mit CSystemItems zu verbinden.
Logischerweise sollen nur zB CTdPlanet eine Verbindung zu einem
CSystemItems haben nicht aber CTdShip. [...]
Es gibt eine Klasse CTdStation welche eine Orbitalstation repräsentiert
die sowohl ein CTdShip (3D-Modell) als auch ein CTdSystemItem (verweis
auf ein CSystemItem) ist.
Das hiesse aber
CTdStation : public CTdShip, public CTdSystemItem
was wenn ich richtig informiert bin nicht geht weil beide von CTdObject
abgeleitet sind.
|
Klar geht das, nur hat TdStation dann zwei TdObject-Subobjekte. Das
ließe sich umgehen, indem du virtuell von TdObject ableitest. Ob das das
ist, was du willst, kann ich nicht beurteilen.
Auch, wenn hier eine C++- und keine Spiele-Gruppe ist, wären ein paar
Hinweise nicht schlecht, welche Eigenschaften die Objekte denn nun
haben. Mir ist z.B. nicht ganz eingängig, warum eine Orbitalstation ein
Schiff sein soll. Nehmen wir mal folgendes an:
.. ein Planet (CTdPlanet) ist fest an ein System gebunden und kann nicht
kämpfen
.. ein Schiff (CTdShip) ist nicht an ein System gebunden, kann aber
kämpfen
.. eine Orbitalstation (CTdStation) ist fest an ein System gebunden,
kann aber kämpfen
Hier hätte die Orbitalstation zwar die Eigenschaft 'kann kämpfen', die
sie vom Schiff erben könnte, erbt aber nicht die Eigenschaft 'kann sich
bewegen', so dass Ableitung das falsche Mittel wäre. Besser wäre hier IMHO
class MovableObject : public CTdObject { ... }
class FixedObject : public CTdObject { ... }
class FightableObject { ... }
class CTdShip : public MovableObject, public FightableObject { ... }
class CTdPlanet : public FixedObject { ... }
class CTdStation : public FixedObject, public FightableObject { ... }
Eine andere Möglichkeit wäre, die Entscheidung, ob ein Objekt kämpfen
bzw. sich bewegen kann, nicht per Ableitung, sondern per Attribut oder
virtueller Funktion zu treffen. Zum Beispiel
class CTdObject {
// Zeiger auf das System, an das dieses Objekt gebunden ist;
// NULL, wenn das Objekt nicht an ein System gebunden ist
CSystemItem* m_pSystem;
};
class CTdShip : public CTdObject { ... }
class CTdPlanet : public CTdObject { ... }
class CTdStation : public CTdObject { ... }
Eine Regel, die ich beim Design für enorm wichtig und hilfreich halte,
ist, dass man möglichst niemals von einer konkreten Klasse ableitet.
CTdShip ist offenbar eine konkrete Klasse; davon eine Orbitalstation
abzuleiten, um ihr kann eigentlich nur zu Problemen führen.
Natürlich gibt es Ausnahmen von der Regel. Beispielsweise kann man
durchaus eine 'Button'-Klasse mit einer virtuellen Methode
'allowClick()' schreiben, die standardmäßig 'true' liefert. Damit wäre
die Klasse 'Button' direkt einsetzbar, man kann aber bei Bedarf eigene
Klassen ableiten, die diese Funktion überschreiben. Das wäre eine
Situation, in der es m.M.n. akzeptabel ist, von einer konkreten Klasse
abzuleiten. Sauberer wäre aber in jedem Fall ein 'AbstractButton', von
dem der 'Button' mit der implementierten 'allowClick()' abgeleitet ist.
Stefan
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
André Schmidt Guest
|
Posted: Sat Feb 05, 2005 4:06 pm Post subject: Re: designfrage |
|
|
Stefan Reuther schrieb:
| Quote: | André Schmidt wrote:
CTdShip public CTdObject - stellt zB. Raumschiffe dar
CTdPlanet public CTdObject - stellt Planeten dar
Ich suche nun einen weg die Td-Objekte mit CSystemItems zu verbinden.
Logischerweise sollen nur zB CTdPlanet eine Verbindung zu einem
CSystemItems haben nicht aber CTdShip. [...]
Es gibt eine Klasse CTdStation welche eine Orbitalstation repräsentiert
die sowohl ein CTdShip (3D-Modell) als auch ein CTdSystemItem (verweis
auf ein CSystemItem) ist.
Das hiesse aber
CTdStation : public CTdShip, public CTdSystemItem
was wenn ich richtig informiert bin nicht geht weil beide von CTdObject
abgeleitet sind.
Klar geht das, nur hat TdStation dann zwei TdObject-Subobjekte. Das
ließe sich umgehen, indem du virtuell von TdObject ableitest. Ob das das
ist, was du willst, kann ich nicht beurteilen.
Was hat das grundsätzlich für einen sinn zwei subobjekte zu haben? Gibt |
es da verwendungen für?
Wie sind denn dann die zugriffsmechanismen? und wie geht das mit dem
virtuellen ableiten? (werd dazu mal googlen)
| Quote: |
Auch, wenn hier eine C++- und keine Spiele-Gruppe ist, wären ein paar
Hinweise nicht schlecht, welche Eigenschaften die Objekte denn nun
haben. Mir ist z.B. nicht ganz eingängig, warum eine Orbitalstation ein
Schiff sein soll.
Es ist tatsächlich so, das ein Ship sowie eine Station zB. kämpfen kann |
(das schliesst ein: Schilde, Schadensberechung, Feuerkraft etc.) und
auch eine 3D-Modell-Datei die zur Darstellung verwendet wird. Planeten
zB. werden generiert und ihnen liegt kein vorgefertigtes Modell zugrunde.
Nehmen wir mal folgendes an:
| Quote: | . ein Planet (CTdPlanet) ist fest an ein System gebunden und kann nicht
kämpfen
. ein Schiff (CTdShip) ist nicht an ein System gebunden, kann aber
kämpfen
. eine Orbitalstation (CTdStation) ist fest an ein System gebunden,
kann aber kämpfen
Hier hätte die Orbitalstation zwar die Eigenschaft 'kann kämpfen', die
sie vom Schiff erben könnte, erbt aber nicht die Eigenschaft 'kann sich
bewegen', so dass Ableitung das falsche Mittel wäre. Besser wäre hier IMHO
class MovableObject : public CTdObject { ... }
class FixedObject : public CTdObject { ... }
class FightableObject { ... }
class CTdShip : public MovableObject, public FightableObject { ... }
class CTdPlanet : public FixedObject { ... }
class CTdStation : public FixedObject, public FightableObject { ... }
Darüber werde ich nochmal nachdenken. Manchmal braucht man echt eine |
externe Meinung wenn man sich schon länger auf ein bestimmtes Schema
eingeschossen hat.
| Quote: | Eine andere Möglichkeit wäre, die Entscheidung, ob ein Objekt kämpfen
bzw. sich bewegen kann, nicht per Ableitung, sondern per Attribut oder
virtueller Funktion zu treffen. Zum Beispiel
class CTdObject {
// Zeiger auf das System, an das dieses Objekt gebunden ist;
// NULL, wenn das Objekt nicht an ein System gebunden ist
CSystemItem* m_pSystem;
};
class CTdShip : public CTdObject { ... }
class CTdPlanet : public CTdObject { ... }
class CTdStation : public CTdObject { ... }
Eine Regel, die ich beim Design für enorm wichtig und hilfreich halte,
ist, dass man möglichst niemals von einer konkreten Klasse ableitet.
CTdShip ist offenbar eine konkrete Klasse; davon eine Orbitalstation
abzuleiten, um ihr kann eigentlich nur zu Problemen führen.
Natürlich gibt es Ausnahmen von der Regel. Beispielsweise kann man
durchaus eine 'Button'-Klasse mit einer virtuellen Methode
'allowClick()' schreiben, die standardmäßig 'true' liefert. Damit wäre
die Klasse 'Button' direkt einsetzbar, man kann aber bei Bedarf eigene
Klassen ableiten, die diese Funktion überschreiben. Das wäre eine
Situation, in der es m.M.n. akzeptabel ist, von einer konkreten Klasse
abzuleiten. Sauberer wäre aber in jedem Fall ein 'AbstractButton', von
dem der 'Button' mit der implementierten 'allowClick()' abgeleitet ist.
Stefan
Vielen Dank für die ausführlichen beispiele. Hat mir sehr geholfen! |
Grüße,
André
--
J.A.E.L.C. - Just another Elite(tm) clone
http://jaelc.szintec.de
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sun Feb 06, 2005 11:42 am Post subject: Re: designfrage |
|
|
André Schmidt wrote:
| Quote: | Stefan Reuther schrieb:
André Schmidt wrote:
Das hiesse aber
CTdStation : public CTdShip, public CTdSystemItem
was wenn ich richtig informiert bin nicht geht weil beide von CTdObject
abgeleitet sind.
Klar geht das, nur hat TdStation dann zwei TdObject-Subobjekte. Das
ließe sich umgehen, indem du virtuell von TdObject ableitest. Ob das das
ist, was du willst, kann ich nicht beurteilen.
Was hat das grundsätzlich für einen sinn zwei subobjekte zu haben? Gibt
es da verwendungen für?
|
Die Regel lautet nun mal einfach, dass jedes 'Derived' ein
'Base'-Subobjekt hat. Und zwar ganz für sich alleine. Hast du also ein
'Derived1' und ein 'Derived2', hast du auch zwei entsprechende
Basisklassen-Subobjekte. Tatsächlich gebraucht hab ich das noch nie,
allerdings bekommt man es leicht, wenn man Markerklassen verwendet (a la
'class my_iterator : public random_iterator_tag, public my_iter_impl').
| Quote: | Wie sind denn dann die zugriffsmechanismen?
|
struct A { int i; }
struct D1 : A { };
struct D2 : A { };
struct M : D1, D2 { };
// ...
M m;
m.D1::i = 1; m.D2::i = 2;
| Quote: | und wie geht das mit dem virtuellen ableiten? (werd dazu mal googlen)
|
Dir Kurzfassung ist: wenn mehrere Klassen (D1, D2) virtuell von einer
dritten Klasse (A) ableiten, hat eine Klasse, die von D1 und D2
ableitet, nur ein A-Subobjekt. Das hat aber u.U. hässliche Auswirkungen
auf die Initialisierung. Ich versuche, wirrtuelle Vererbung zu
vermeiden, wo es geht. Und bis jetzt hab ich das auch gut geschafft.
Stefan
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|