Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
10.12.2001, 00:10
Nicemice
Moderator


Also ich hab einen Pointer auf ein Objekt vom Typ CBaseEntity. Davon gibts eine abgeleitete Klasse Namens CBasePlayer.
Wie kann ich nun 'testen', ob der Pointer auf ein CBaseEntity Objekt oder auf ein CBasePlayer Objekt zeigt ?
und wenn ich dann weiß, daß es ein CBasePlayer Objekt ist, wie kann ich aus dem CBaseEntity Pointer dann so zusagen einen CBasePlayer pointer machen ? (dereferenzieren und wieder zurück ?)

--

www.d3opencoop.com - A Doom3 Cooperative Mod

zum Seitenanfang zum Seitenende Profil || Suche
001
10.12.2001, 00:43
Tron



1. lies mal was ueber RTTI nach
2. ganz einfach casten

aber das sollte nicht noetig sein, wenn das sauberes oo ist und das interface in der basisklasse festgelegt ist und alle entsprechenden methoden schoen brav virtuell sind
aber CBaseEntity hoert sich schwer nach hl-sdk an, also vergiss den letzten satz (;

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
002
10.12.2001, 01:08
Kriz



Das ist pure Objektorientierung.

Genau dein Thema habe ich aber bereits hier schon fett ausgezwiebelt (Forumsuche). Zu deinem Problem aber trotzdem:

CBasePlayer besitzt als Subobjekt stets CBaseEntity. Das bedeutet, daß man bei einem CBasePlayer-Objekt auf die Eigenschaften von CBasePlayer zugreifen kann als auch auf die darunterliegende Ebene von CBaseEntity. Gerade der Ansatz mit Zeigern ist lobenswert, wenn auch hinterhältig.

Prüfung auf Klassenzugehörigkeit

Leider ist C++ da nicht so elegant wie Java, wo man mittels dem instanceof Operator sowas testen kann. In C++ kann man sowas prüfen, indem man einen umständlichen Vergleich anstellt:
Quellcode:#include <typeinfo>
class CBaseEntity {};

class CBasePlayer : public CBaseEntity {};

void main()
{
....CBaseEntity obj; // Referenzinstanz
....CBasePlayer p1; // Referenzinstanz
....CBaseEntity *pObj = &p1; // Basiszeiger zeigt auf CBasePlayer-Instanz
....if(typeid(p1) == typeid(CBaseEntity)) ... // Stammt von Klasse CBaseEntity
...else if(typeid(p1) == typeid(CBasePlayer)) ... // von CBasePlayer
...else // weder noch
}

Wie gesagt, nicht sehr elegant. Eine andere Möglichkeit ist, mit Strings zu prüfen:
Quellcode:
#include <typeinfo>
#include <string.h>

// wie gehabt

void main()
{
....// Wie gehabt
....if(!strcmp(typeid(*p1), "class CBaseEntity")) ... // von CBaseEntity
....else if(!strcmp(typeid(*p1), "class CBasePlayer")) ... // von CBasePlayer
....else ... /// weder noch

C++ hat in diesem Bereich irgendwie Defizite O_o

Konvertieren von Abgeleitet auf Basis

Das geht nur, wenn man einen Zeiger auf die Basisklasse hat und das abgeleitete Objekt darauf umwandelt. Man kann nicht einen abgeleiteten Zeiger nehmen und diesen sich selbst auf Basis casten lassen:
Quellcode:p1 = static_cast<Basis*>(p1); // Geht nicht
Und zwar deshalb nicht, da CBasePlayer Eigenschaften hat infolge der Vererbung, die CBaseEntity nicht kennt. Zwar besitzt der Zeiger p1 die Klasse CBaseEntity als Unterobjekt, aber die Konvertierung würde Eigenschaften aus CBasePlayer mitbringen, mit denen CBaseEntity nichts anfangen kann. Das Problem kann man nur so lösen:
Quellcode:CBaseEntity be;
CBasePlayer bp;
CBaseEntity *pbe = &be;
CBasePlayer *pbp = &bp;

pbe = reinterpret_cast<CBaseEntity*>(pbp);

Der alte C Stil geht zwar auch...
Quellcode:...
pbe = (Basis*) pbp;

...aber ist nicht zu empfehlen, wenn man C++ programmiert, da die cast-Operatoren aus C++ Typprüfungen vornehmen. Reinterpret_cast z.B. nimmt die Typprüfung zur Compile-Zeit vor, also bevor die Scheiße kochen kann. Dynamic_cast dagegen erst zur Laufzeit, wobei dann bei einem Fehler eine Exception geworfen wird vom Typ bad_cast.

Ob das dann alles in allem auch den gewünschten Effekt hat, den man sich erhofft, bleibt wegen des Verlustes der Eigenschaften von CBasePlayer wohl aus...

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)


Dieser Beitrag wurde am 10.12.2001 um 01:37 von Kriz bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
003
10.12.2001, 07:12
Tron



@Kriz:
das ist mir neu, dass reinterpret_cast irgendetwas ueberprueft.
ich dachte, das macht einfach 'ne binaere kopie des zeigers

also:
Quellcode:
class SomeClass {};
class SomeToatalDifferentClass {};

void main()
{
  SomeClass obj;
  SomeToatalDifferentClass* ptr;
  ptr = reinterpret_cast<SomeToatalDifferentClass> obj;
}

ich dachte static_cast waere dafuer gedacht:
casten von kind auf basisklasse (ist immer gueltig)
casten von basis auf kindklasse (geht auch, ist aber unsicher)
static_cast laesst also nur casten zwischen verwandten klassen zu

Quellcode:
class SomeClass {};
class SomeDerivedClass : public SomeClass {};
class SomeToatalDifferentClass {};

void main()
{
  SomeClass obj;
  SomeDerivedClass* ptr1;
  SomeToatalDifferentClass* ptr2;
  ptr1 = static_cast<SomeDerivedClass> obj; // geht, ist aber nicht sicher
  ptr2 = static_cast<SomeToatalDifferentClass> obj; // compiler-fehler
}

oder bin ich da jetzt auf dem holzweg?

<edit>
ich dachte auch, dass dynamic_cast einen null-zeiger zuruckgibt falls die umwandlung nicht gueltig ist. (und keine exception wirft)

Quellcode:
class SomeClass {};
class SomeDerivedClass : public SomeClass {};
class SomeToatalDifferentClass {};

void main()
{
  SomeClass obj1;
  SomeDerivedClass obj2;

  SomeClass* ptr1 = &obj1;
  SomeClass* ptr2 = &obj2;

  SomeDerivedClass* ptra;
  SomeDerivedClass* ptrb;

  ptra = dynamic_cast<SomeDerivedClass> obj1; // ptra == NULL
  ptrb = dynamic_cast<SomeDerivedClass> obj2; // ptrb ist gueltig
}

</edit>

nur wenn man referencen ungueltig castet wird eine exception geworfen, oder?

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett


Dieser Beitrag wurde am 10.12.2001 um 07:19 von Tron bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
004
10.12.2001, 11:10
Kriz



Hab ich irgendwo gesagt, daß die Umwandlung mit static_cast nicht geht? Nur reinterpret_cast haut richtig rein, auch in den Fällen, wo static_cast möglicherweise versagt.

Das mit dynamic_cast ist so:

ziel = dynamic_cast<T>(Quelle);

Falls Quelle ein Zeiger ist, der nicht auf ein Objekt vom Typ T oder auf ein abgeleitetes Objekt von T zeigt, wird der NULL-Zeiger zurückgegeben.

Falls Quelle eine Referenz ist, die nicht auf ein Objekt vom Typ T oder auf ein abgeleitetes Objekt von T zeigt, wird bad_cast geworfen.

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)

zum Seitenanfang zum Seitenende Profil || Suche
005
10.12.2001, 16:07
Another1



nunja, wollen wir mal zur praxis übergehen:
da es sich hierbei um HalfLife handelt, würde ich auch einfach die Methoden nehmen, die HalfLife einem zur verfügung stellt:

1. Allgemeingültige Prüfung
anhand des entvars_t::classname feststellen, zu welcher klasse das entity gehört

if(FStrEq(STRING(pEntityPtr->pev->classname),"mein_besonderes_entity"))
CBesonderesEntity* pBE = (CBesonderesEntity*)pEntityPtr;

2. Für Player
für Player gibt es schon eine virtuelle Funktion, die nur für CBasePlayer instanzen true zurück gibt, undzwar bool CBaseEntity::IsPlayer()
die sollte es in deinem Fall auch bringen.

--

Another1

...relaxing..atm =)
... und Schweiz suckt!

zum Seitenanfang zum Seitenende Profil || Suche
006
11.12.2001, 17:56
Prefect



C++ hat halt wenigstens noch ein kleines Bißchen (naja, ne ganze Menge ;)) der Schönheit von C.

Wer RTTI in einer _wirklich_ flexiblen, kompilierten General Purpose-Sprache haben will hat eigentlich irgendwas falsch verstanden. Zum Glück kann man RTTI auch deaktivieren.

Und wenn du's tatsächlich brauchst kannst du RTTI auch selber programmieren -> siehe Qt.

Ich hab jetzt keine Lust, meine Meinungen weiter zu begründen. Erstens bin ich dazu zu müde, zweitens haben wir das eh schon viel zu oft durchgekaut.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
007
11.12.2001, 18:43
Nicemice
Moderator


... und mir reicht another1's methode.

--

www.d3opencoop.com - A Doom3 Cooperative Mod

zum Seitenanfang zum Seitenende Profil || Suche
008
12.12.2001, 14:35
TheVoice



Schöner Thread!

Ich glaube dieses Problem werde ich auch in meinem Tutorial zur OOP behandeln :)

--

Against TCPA | Resourcecode.de | Blender 3D | [ Darkzone | Pandorra | Alpine ]

zum Seitenanfang zum Seitenende Profil || Suche