Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

RmbRT

Treue Seele

  • »RmbRT« ist der Autor dieses Themas

Beiträge: 169

Wohnort: Darmstadt

Beruf: Student

  • Private Nachricht senden

11

29.08.2012, 17:16

Ich habs jetzt noch mal komplett neu geschrieben, das "#define is" hat in irgend einem std header fehler verursacht. jetzt ohne struct sondern mit dynamic_cast (man lernt ja immer was dazu :thumbup: ), d.h., es überprüft nicht mehr zur compile zeit sondern zur laufzeit.
also für alle, die es sehen wollen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template<class Other, class T>
inline const bool is_typeof_runtime(T*x, const Other*)
{
    return (bool)dynamic_cast<Other*>(x);

    return false;
}

template<class Other, class T>
inline const bool is_typeof_runtime(T&x, const Other*)
{
    try
    {
        return (bool)dynamic_cast<Other&>(x);
    }
    catch(...)
    {}
    return false;
}

#ifndef __TYPED_MACRO__
#define typeof is_typeof_runtime(
#define equals(type) ,static_cast<type*>(0))
#endif


und dann so benutzen:

C-/C++-Quelltext

1
if(typeof MeineTolleVariable equals(MeineTolleKlasse)) //...

MfG, RmbRT
"Dumm ist, wer dummes tut."

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »RmbRT« (29.08.2012, 20:22)


CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

12

29.08.2012, 17:37

Ich habs jetzt noch mal komplett neu geschrieben, das "#define is" hat in irgend einem std header fehler verursacht

Es gibt einen guten Grund, warum man Makros meidet (Alliteration, gut merkbar!), erst recht solche. Mit jedem Makro, das du einführst, machst du den Namen des Makros für alle anderen Teile des Programms (inklusive externe Bibliotheken!) unbenutzbar.

Warum nicht einfach if (dynamic_cast<Foo*>(somePtr)) direkt im Code? Dann würdest du auch feststellen, dass innerhalb des if-Zweigs praktisch zwangsläufig nochmal gecastet wird, und könntest den Cast gleich rausziehen: Foo *foo = dynamic_cast<Foo*>(somePtr); if (foo) { use foo ... }. (Selbst if (auto foo = dynamic_cast<Foo*>(somePtr)) { use foo ... } ist erlaubt).

Wenn du unbedingt eine Hilfsfunktion willst (in anderen, sinnvolleren Fällen!), dann spricht auch nichts gegen eine Notation wie if (is_typeof_runtime<Foo>(somePtr)), zumal dann jeder sofort weiß, was los ist, anstatt von mit Makros hingehackten sprachfremden Konstrukten überrascht zu werden.

Und schließlich ist praktisch jeder Fall, in dem du den Laufzeittyp eines Objekts zu bestimmen versuchst, ein Fehler. Eine entsprechende Hilfsfunktion und gar eine eigene Syntax dafür kommt also dem Vorsatz gleich, maximal viele Fehler zu machen.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

13

29.08.2012, 18:14

Abgesehen davon: dynamic_cast in einen Pointertyp liefert einen Nullpointer wenn er nicht funktioniert und wirft keine Exception. Und statt dem catch (...) wäre wohl ein catch (const std::bad_cast&) besser.

RmbRT

Treue Seele

  • »RmbRT« ist der Autor dieses Themas

Beiträge: 169

Wohnort: Darmstadt

Beruf: Student

  • Private Nachricht senden

14

29.08.2012, 20:05

@CodingCat: Ja da kann ich dir nur zustimmen, das ist schlechter Stil, aber ich experimentiere halt gerne rum und hätte auch gar keine so wichtige verwendung dafür. Und habe ich es in eine Funktion gepackt, da dynamic_cast<T&> auch werfen kann. Aber es ist nicht immer ein Fehler, den Laufzeittyp des Objektes zu bestimmen, denke mal an:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Klassen-Hirarchie
class GameObject { virtual _unused_function();/*um GameObject Polymorph zu machen*/};
class Player : public GameObject { };
class Tank : public Player {};
class Sniper: public Player{};

//und dann in einer Funktion
void react(GameObject*obj)
{
    if(is_typeof_runtime<Player>(obj))
    {
        if(is_typeof_runtime<Sniper>(obj))
            GreifeOffensivAn(obj);
        else if(is_typeof_runtime<Tank>(obj))
            if(hp > 50)
                GreifeOffensivAn(obj);
            else
                FlüchteVor(obj);
    }
    else
    {
        //z.b. explodierendes Fass, ein Auto, eine Heilstation etc...
    }
}

@dot: Okay, danke für die info ;)
MfG, RmbRT
"Dumm ist, wer dummes tut."

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

15

29.08.2012, 20:54

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
class GameObject
{
public:
   virtual void react() = 0;
};

...

void react( GameObject* obj )
{
   obj->react();
}


In der react Methode interessiert es mich nun nicht mehr was für ein Objekt ich übergeben bekomme...
Wie reagiert wird entscheidet dann eben das objekt, in dem in der Klasse eben die react Methode implementiert wird.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

16

29.08.2012, 22:29

Aber es ist nicht immer ein Fehler, den Laufzeittyp des Objektes zu bestimmen, denke mal an:

Gerade dieser von Dir gezeigt Code ist ein Paradebeispiel von schlechtem Design und genau das, was dot gemeint hat. Da liegt etwas im Argen und sollte behoben werden. Die Verwendung von impliziten Wissen stört mich an dem Code persönlich am meisten, sowie das Vorhandensein einer zentralen und globalen Stelle für KI-Entscheidungen, die auf generellen Attributen statt auf Klassifizierungen beruhen und vor allem nicht hardcoded sein sollten. Meine Meinung.

@Sylence:
Dieser Vorschlag funktioniert sicher auch nicht sonderlich gut, denn dem Reagierenden ist bei Deiner Variante gar nicht klar auf was oder wen überhaupt zu reagieren ist und welche Art von Reaktion sinnvoll wäre. Es macht für einen Tank einen Unterschied, ob er von einem Tank, einem Dagger oder Archer angegriffen wurde. Nur so als Beispiel ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (29.08.2012, 22:34)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

17

29.08.2012, 23:24

Eine Lösung für das Problem wäre in diesem Fall beispielsweise ein Double Dispatch bzw. das Visitor Pattern.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (29.08.2012, 23:30)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

18

30.08.2012, 08:15

Jap. Genau an so eine Lösung hätte ich dabei auch gedacht. Wobei man den Visitor dann als "KI" bezeichnen könnte, von der jeder Klassen-Typ genau eine spezifische besitzt. Großer Nachteil bei diesem Entwurf wäre, dass jede Klasse eine KI kennt und diese wiederum alle anderen Typen, was eine hässliche zirkuläre Abhängkeit wäre (Tank kennt KI, Dagger kennt KI, KI kennt beide). Diese ließe sich aber prima durch Interfaces auflösen und das Problem wäre gegessen. Dann kennen sich maximal die Interfaces, was ich verkraften könnte. dot, hast Du 'ne Idee, wie man das (auch wenn das jetzt alles rein theoretisch ist) eventuell komplett auflösen könnte? Komplette Auslagerung der KIs/Visitors wäre eine Lösung, welche sowohl den Nach- und Vorteil der Dezentralität hätte.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige