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

Whitethunder

Frischling

  • »Whitethunder« ist der Autor dieses Themas

Beiträge: 7

Beruf: Schüler

  • Private Nachricht senden

1

24.02.2008, 21:04

Fehler beim Instanz erstellen erkennen u. and. Unklarheiten

Wie ihr aus dem Titel entnehmen könnt, habe ich noch ein paar Unklarheiten, von denen ich hoffe, dass ihr sie beseitigen könnt^^

1. Ich habe eine Spielklasse, die in ihrem Konstruktor die verwendeten Engines initialisiert. Nun könnte es ja vorkommen, dass eine dieser Engines aus irgendeinem Grund nicht initialisiert werden kann. In diesem Fall wird im Konstruktor eine MessageBox mit einer Fehlermeldung aufgerufen und danach "return 1;".
Das Erstellen der Instanz habe ich so gemacht:

C-/C++-Quelltext

1
2
3
4
if(CMyGame Game)
{
    return 1;
}

Natürlich ist das nur ein Beispiel und nicht der ganze Code xD
So wie ich mir das dachte, wird in der if-Bedingung die Instanz erstellt und falls ein Fehler auftritt liefert der Konstruktor 1 zurück, was die Bedingung erfüllt und das Programm beendet. Nun bin ich mir überhaupt nicht sicher, ob das so zulässig ist xD Hoffe ihr könnt mich aufklären und evtl. eine andere Lösung vorschlagen...

2. Das mag jetzt vielleicht das falsche Unterforum sein, um das zu fragen, weil es ne Frage zum Buch "3D Spieleprogrammierung" ist...
In den Listings 9.50, 9.51 und 9.52 werden die Konstruktoren der abstrakten Klasse über den ":" Operator mit anderen Konstruktoren verbunden... z.B.:

C-/C++-Quelltext

1
2
3
4
5
6
7
class CGame
{
    //...

    public:
        CGame() : m_pGameState(NULL) {}
    //...

};

Nun meine Frage: Was hat es damit auf sich? Das hab ich bis jetzt noch nicht gesehen und eine Google-Suche nach dem :-Operator hat mir auch nichts gebracht...

Herzlichen Dank im Voraus^^

PS: Ich denke mir einfach mal, dass das hier unter C++ Allgemein fällt? Ansonsten entschuldige ich mich...

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

2

24.02.2008, 21:20

Also Konstruktoren haben keine Rückgabewerte, also macht das keinen Sinn. Aber die Engine wird sicher irgendwas haben, dass dir dann sagt, ob das initialisieren geklappt hat. Und DAS kannst du dann überprüfen.

Zitat

CGame() : m_pGameState(NULL) {}


Das ist eine Initialiserungsliste. Das ist die einzige Möglichkeit Klassenmember zu initialisieren.

Nicht zu verwechseln mit der Zuweisung:

C-/C++-Quelltext

1
CGame() { m_pGameState = NULL}


Kommt hier auf etwa das gleiche raus.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

3

24.02.2008, 21:20

Zur ersten Frage: Ein Konstruktor liefert keinen Wert zurück, deshalb ist dein Vorgehen nicht korrekt. Wirf eine Ausnahme, wenn dein Objekt nicht initialisiert werden kann.

Zur zweiten Frage: Das was du meinst nennt sich Initialisierungsliste. Diese Liste erlaubt es Objekte wirklich zu initialisieren. Wenn du die "initialisierung" erst im Konstruktorrumpf vornimmst, sind alle Objekte schon mit Standardwerten initialisiert, d.h. du hast mehr Arbeit. Außerdem spart sich der Compiler den Aufruf des Konstruktorrumpfes wenn alle Objekte in der Initialisierungsliste initialisiert werden.
@D13_Dreinig

4

24.02.2008, 22:39

1: Ausnahmen/Exception's oder Errorflags sind die Lösung deines Problems. Ein Konstruktor kann keinen Wert zurück geben.

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
struct foo
{
    foo(const std::size_t bar)
    {
        if (bar > 10) throw std::invalid_argument("to large");
        std::clog << "{c-tor}: \n-> bar := \"" << bar << "\";" << std::endl;
    }
};

int main()
{
    try
    {
        foo first(10);
        foo second(11);
    } catch(std::invalid_argument const& ex)
    { 
        std::cerr << "FEHLER: " << ex.what() << std::endl; 
        return 1;
    }
    return 0;     
}
so ... da sollte er erst

Quellcode

1
2
{c-tor}: 
-> bar := "10"; 
ausgeben und dann

Quellcode

1
FEHLER: to large
, da du die Ausnahme, die der c-tor von foo geworfen hast (invalid_argument) abgefangen hast(catch).

2.
Initialisierungsliste. Wo du ohne nicht ohne weiters auskommst:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class foo
{
    unsigned int id;

public:
    foo(const unsigned int id)
        : id(id)
    {}
};

class bar
{
    foo m_foo;
    
public:
    bar()
       : m_foo(1) // Hier brauchst du sie spätestens ;)

    {}
};
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

Whitethunder

Frischling

  • »Whitethunder« ist der Autor dieses Themas

Beiträge: 7

Beruf: Schüler

  • Private Nachricht senden

5

24.02.2008, 22:40

Zu 1.: Danke, hat mir sehr geholfen, werds dann über try, catch und throw machen^^

Zu 2.: Eine Initialisierungsliste... Ach so! xD
Wenn ich das jetzt richtig verstanden hab, wird durch

C-/C++-Quelltext

1
CGame() : m_pGameState(NULL) {}

also der Zeiger beim Erzeugen der Instanz vor dem Konstruktoraufruf gleich auf NULL gesetzt? Sprich, es ist performanter als eine Initialisierung im Konstruktor, hat aber den gleichen Effekt?

6

24.02.2008, 22:49

Jap. Bzw. eine Quizfrage:
Wird bei einem Zeiger ein Konstruktor Aufgerufen? (Wenn dieser bsw. auf NULL gelenkt wird)

Ob du nun einen Default-Konstruktor eines Objektes und danach noch den Zuweisungsoperator aufrufst (oder ggf. eine Funktion), oder nur einen Konstruktor, direkt mit entsprechenden Werten, macht einen Unterschied.
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

Whitethunder

Frischling

  • »Whitethunder« ist der Autor dieses Themas

Beiträge: 7

Beruf: Schüler

  • Private Nachricht senden

7

24.02.2008, 22:57

Zur Quizfrage: Hmm... Lass mich nachdenken... Nach dem Prinzip der Objektorientiertheit is ALLES ein Objekt, also auch ein Zeiger. Daher muss bei jeder Erzeugung ein Konstruktor aufgerufen werden, sei es nun eine Klasse, eine Struktur, ein Zeiger oder auch ein harmloses int. Oder? xD

Ja, der Unterschied ist, dass ich beim Ersteren zwei oder mehr Aufrufe habe und beim Zweiten nur insgesamt einen... Denke ich xD

8

25.02.2008, 15:49

Der springende Punkt mit der Initialisierungsliste ist doch:
Wenn eine Klasse sich bereits im konstruktor initialisiert und es Werte gibt, die nach der Initialisierung gleich bleiben müssen - also nur über konstruktorparameter angegeben werden können - ist die Initialisierungsliste die einzige Möglichkeit, diese Klasse in einer anderen direkt (ohne zeiger) zu verwenden.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

9

25.02.2008, 16:28

@PCShadow:
Zum einen ist die Initialisierungsliste die einzige Möglichkeit einen bestimmten Konstruktor einer Basisklasse aufzurufen, zum Anderen dient sie dazu Instanzen wirklich zu initialisieren, was spätestens bei Referenzen notwendig ist.
@D13_Dreinig

Beneroth

Alter Hase

Beiträge: 969

Wohnort: Schweiz

Beruf: Software Entwickler

  • Private Nachricht senden

10

26.02.2008, 11:05

Zitat von »"Whitethunder"«

Nach dem Prinzip der Objektorientiertheit is ALLES ein Objekt


Ist in neueren OO-Sprachen wie C# und Java vollkommen oder sehr weitgehend so. Bei C++ ist das falsch, vorallem da C++ nicht eine reine OO-Sprache ist.

Zitat von »"Whitethunder"«

Daher muss bei jeder Erzeugung ein Konstruktor aufgerufen werden, sei es nun eine Klasse, eine Struktur, ein Zeiger oder auch ein harmloses int. Oder? xD

Ja, der Unterschied ist, dass ich beim Ersteren zwei oder mehr Aufrufe habe und beim Zweiten nur insgesamt einen... Denke ich xD


Alles braucht Speicher, speicher muss zuerst reserviert werden. Ein Konstruktor wird abr nur bei Klassen (oder c++ structs) aufgerufen, und zwar nachdem das Objekt eigentlich erstellt und Speicher reserviert wurde.

Werbeanzeige