Klasse eines Objekts ermitteln



  • Hi,

    danke für die Antwort.

    Aber leider wird hier immer nur Base ausgegeben.

    Ich benötige aber die Info, ob ich ein Objekt der Ableitung habe.



  • @Braunstein:

    Ich habe ein Spiel, bei dem man entweder gegen den PC oder gegen einen echten Gegner spielen kann.

    Die Basisklasse "Spieler" wird benutzt, wenn ich gegen einen echten Spieler spiele. Die Klasse "Computer" leitet von "Spieler" ab und wird benutzt, wenn ich gegen den PC spiele.

    Um jetzt aber herauszufinden, ob mein gegner der PC oder der Spieler ist, benötige ich diese Info.



  • Musst du dann zusätzliche Funktionen aufrufen, wenn der Gegner der Computer ist?
    Wenn nicht, müßtest du nicht ableiten, dann würde es doch reichen, wenn deine Klasse eine Funktion wie isComputer() bereitstellt.
    Du könntest auch zwei Listen halten, eine für normale Spieler und eine für Computergegener.
    Versuche erstmal dein Design so zu verändern, dass du nicht herausfinden musst welche Klasse es ist.
    Siehe auch Thema Polymorphie.



  • Irgendwie hast du Recht... Bin noch neu in C++ und bisher von PHP verwöhnt

    Ne allgemeine Frage:

    Die Klicks werden bei mir so entgegen genommen:

    void __fastcall Controller::onClick(TObject *Sender)
    {
    Feld *feld = NULL;                  //Temporärer Speicher für Felder
    Spieler *winner = NULL;             //Temporärer Speicher für den Gewinner-Spieler
    feld = dynamic_cast<Feld*>(Sender); //Sender-Objekt wird zu Feld-Objekt gecastet
    
    if(this->isFinished())  //Falls das Spiel beendet wurde, wird abgebrochen
    {
      return;               //Abbrechen
    }
    
    if(feld->isEmpty())  //Man darf nur leere Felder anklicken
    {
     feld->setColor(this->counter % 2 == 0 ? this->spieler[0]->getColor() : this->spieler[1]->getColor());
     feld->setPlayer(this->counter % 2 == 0 ? this->spieler[0] : this->spieler[1]);
     this->counter++;
    }
    
    this->gui->setStatusMessage("Spieler '" + this->spieler[this->counter % 2 == 0 ? 0 : 1]->getName() + "' ist dran!");
    
    winner = this->checkField(); //Das Spielfeld nach dem Gewinner durchsuchen
    if(winner != NULL)        //Wenn winner != NULL ist, gibt es einen Gewinner.
    {
      this->gui->setStatusMessage(winner->getName()+" hat gewonnen!");
      this->setFinished(true);
    }
    else
    {
      //Auf unentschieden prüfen
      int volle_felder = 0;  //Wieviele Felder sind bereits belegt?
    
       //In dieser verschachtelten for-Schleife wird ermittelt, wieviele Felder belegt sind.
       for(int y = 0; y < CONST__anzY; y++)
       {
         for(int x = 0; x < CONST__anzX; x++)
         {
           if(!this->model->getFeld(x,y)->isEmpty())
           {
             volle_felder++;    //Ein belegtes Feld mehr
           }
         }
       }
    
       //Entspricht die Anzahl der vollen Felder der Anzahl der vorhandenen Spielfelder?
       if(volle_felder >= (CONST__anzX * CONST__anzY))
       {
         this->gui->setStatusMessage("Untentschieden");
         this->setFinished(true);
       }
    }
    
    }
    

    Es wird geprüft, welcher Spieler dran ist (Momentan wird noch nicht zwischen PC und Mensch unterschieden)

    Wie baue ich hier am besten den Zug des PCs mit ein?
    Einfach eine Methode namens PC() schreiben und die dann nach jedem Klick aufrufen, wenn der Gegner kein Mensch ist?

    Und wie handhabe ich die verschiedenen Schwierigkeitsstufen? Dazu müsste ich eigentlich nochmal ableiten.

    Computer_Einfach & Computer_Schwer

    Seh ich das richtig?



  • Du musst nicht soviel ableiten.
    Verwende nur eine Spielerklasse welche die schon ober erwähnte Funktion anbietet.
    Die Schwierigkeitsstufen sollten eigentlich nicht im Spieler festgelegt sein sonst würden die Spieler ja auf unterschiedliche Stufen spielen können was für mich widersinnig klingt. Meiner meinung nach gehört die Schwierigkeit in den Controller.
    Packe bitte nicht den ganzen Code in die OnClick-Routine sondern lagere den in eine eigene Funktion aus. Am besten in eine separate Controler-Klasse.



  • Ich soll also nur eine Klasse "Spieler" haben und dann anhand von Attributen unterscheiden, ob es ein PC oder ein Mensch ist? Wenn PC, dann noch ein zusätzliches Attribut, das die Schwierigkeit enthält.

    In den Spieler-Klassen soll ich KEIN Verhalten des PCs implementieren, sondern das alles in den Controller auslagern?

    Hab ich das so richtig verstanden?

    Die Spieler sind sozusagen Models, die nur Informationen speichern, aber keine Logik enthalten.

    Packe bitte nicht den ganzen Code in die OnClick-Routine sondern lagere den in eine eigene Funktion aus. Am besten in eine separate Controler-Klasse.

    Ok, aber was spricht dagegen?
    Und wozu eine separate Controller-Klasse? das versteh ich nicht



  • Die Controller Klasse dient dazu, die Programmlogik von der GUI zu trennen. Ausserdem schaffst du dadurch eine klar definierte Struktur in deinem Projekt mit der es später einfacher ist Funktionalität zu ergänzen oder Komponenten auszutauschen. Durch das MVC (Model-View-Controller) Konzept sind die Aufgaben klar verteilt und durch entsprechende Interface Spezifikation kann jeder View durch einen anderen ausgetauscht werden. Das könnte bei dir zB. der Fall sein, wenn das Spiel statt in einem VCL Formular in der Konsole gespielt werden soll, dann musst du die ganze Programmlogik nicht noch einmal für die Konsole programmieren, sondern dich nur um die Eingabe und Ausgabe aus/auf der Konsole kümmern, den Rest erledigt der Controller.

    Ich finde, dass es schon Sinn macht, zwei unterschiedliche Typen für Menschen und PC Gegner zu haben, sie sollten allerdings von einer gemeinsamen Basisklasse erben. Von TObject abzuleiten halte ich für nicht gut, da man sich dadurch eine Menge überflüssiger Delphi/C++ Probleme einhandelt. Für nichtvisuelle Klassen ist man mit Standard C++ und der STL mMn besser bedient.



  • Den ersten Absatz hab ich verstanden.

    Den zweiten allerdings nicht:

    Ich finde, dass es schon Sinn macht, zwei unterschiedliche Typen für Menschen und PC Gegner zu haben, sie sollten allerdings von einer gemeinsamen Basisklasse erben. Von TObject abzuleiten halte ich für nicht gut, da man sich dadurch eine Menge überflüssiger Delphi/C++ Probleme einhandelt. Für nichtvisuelle Klassen ist man mit Standard C++ und der STL mMn besser bedient.
    

    Was sollte in meinem Fall die gemeinsame Basisklasse sein?

    Ich würde eine abstrakte Klasse Spieler anlegen, die die Funktionalitäten enthält, die alle Unterklassen brauchen (Farbe setzen, Name setzen, alles auslesen)
    Dann eine Klasse Mensch, allerdings weiß ich hier nicht, was diese Klasse haben sollte, was Spieler nicht hat.
    Jetzt brauche ich noch die Klasse "Computer".

    Aber so wirklich viel bringen wird es mir nicht....

    Hätte nicht gedacht, dass ich jetzt DARAN scheitere. Der Rest ist shcon fertig programmiert und funktioniert.



  • Jut, dann lass es doch so, wie es gerade ist. So etwas im Nachhinein zu ändern wird oft aufwändiger als einem lieb ist.

    Wirklich viele unterschiedliche Unterscheidungsmerkmale für HumanPlayer/ComputerPlayer fallen mir jetzt auch nicht ein, ausser dass der ComputerPlayer evtl. ein Attribut für die Spielstärke hat. Wenn das der Fall wäre könnte man zB. Computergegner unterschiedlicher Spielstärke gegeneinander antreten lassen. Aber du kennst dein Projekt besser als ich, und wenn du keinen Sinn darin siehst ist es vermutlich richtig.



  • Dann lasse ich es jetzt so, wie es ist.

    Aber dann brauche ich ja doch noch die Unterscheidung zwischen Mensch und PC.

    Was ist, wenn ich einfach eine Methode "getType()" schreibe, die in der Klasse Mensch "Mensch" zurückgibt und beim PC "Computer"? Wäre das sauber so?



  • Tag,
    ich habe es jetzt so gemacht:

    Es gibt eine Klasse "Spieler" (abstrakt), von der "Mensch" und "Computer" abgeleitet werden. Den Code poste ich hier nicht, der ist nicht relevant.

    Aber eines stört mich bisher gewaltig.

    Ich kann den Zug des PCs erst veranlassen, wenn die onClick-Methode eines Felds aufgerufen wird. Hier der Code:

    // Diese Methode regelt den Spielablauf. Mit dem ersten Klick eines Spielers beginnt das Spiel.
    // Ist der zweite Spieler der PC, wird automatisch die entsprechende Methode aufgerufen.
    void __fastcall Controller::onClick(TObject *Sender)
    {
    Feld *feld = NULL;                  //Temporärer Speicher für Felder
    feld = dynamic_cast<Feld*>(Sender); //Sender-Objekt wird zu Feld-Objekt gecastet
    
    if(this->isFinished())  //Falls das Spiel beendet wurde, wird abgebrochen
    {
      return;               //Abbrechen
    }
    
    if(feld->isEmpty())  //Man darf nur leere Felder anklicken
    {
     feld->setColor(this->getCurrentPlayer()->getColor());
     feld->setPlayer(this->getCurrentPlayer());
     this->counter++;
    }
    
    this->gui->setStatusMessage("Spieler '" + this->getCurrentPlayer()->getName() + "' ist dran!");
    
    this->searchWinner();
    
    if(this->getCurrentPlayer()->getType() == "Computer")
    {
      this->zugPC();
      this->searchWinner();
    }
    
    this->gui->setStatusMessage("Spieler '" + this->getCurrentPlayer()->getName() + "' ist dran!");
    
    }
    

    searchWinner()

    void Controller::searchWinner()
    {
    Spieler *winner = NULL;             //Temporärer Speicher für den Gewinner-Spieler
    winner = this->checkField(); //Das Spielfeld nach dem Gewinner durchsuchen
    if(winner != NULL)        //Wenn winner != NULL ist, gibt es einen Gewinner.
    {
      this->gui->setStatusMessage(winner->getName()+" hat gewonnen!");
      this->setFinished(true);
    }
    else
    {
      //Auf unentschieden prüfen
      if(this->isUnentschieden())
      {
       this->gui->setStatusMessage("Untentschieden");
       this->setFinished(true);
      }
    }
    }
    

    zugPC()

    void Controller::zugPC()
    {
     static int t = 0;
     Application->ProcessMessages(); //GUI aktualisieren lassen
     Sleep(500);   //Kurz warten, um "Computer ist dran" noch stehen zu lassen
     this->model->getFeld(t%3,0)->setColor(this->getCurrentPlayer()->getColor());
     this->model->getFeld(t++%3,0)->setPlayer(this->getCurrentPlayer());
     this->counter++;
    }
    

    Beim Zug des PCs fehlt noch die Unterscheidung zwischen den Schwierigkeitsstufen.
    Momentan wird nur die linke Zeile des Felds beschrieben.

    Wie ist das so bis jetzt? Kann man es so lassen oder ist es eher schlecht?

    OOP-Gott



  • Sehe gerade, dass ich so keine 2 PC-Spieler gegeneinander spielen lassen kann.

    Ich wusste doch, dass das mit dem onClick hässlich ist 😃

    Hat jemand eine Idee, wie ich das anders machen kann?

    Ich muss ja - falls ein Spieler ein Mensch ist - Trotzdem auf klicks reagieren können.


Anmelden zum Antworten