Virtuelle Funktion



  • Hallo zusammen,

    ich habe eine abstrakte Basisklasse Player, von der die Klassen HumanPlayer und AIPlayer erben. Der Spielername soll über die rein virtuelle Funktion generateName() ermittelt. Player bietet hiefür jedoch eine Standartimplementierung an. AIPlayer ruft diese auf, HumanPlayer soll den Benutzer nach einem Namem fragen.

    Ich wollte im Konstruktor von Player generateName() aufrufen und hatte gedacht, dass wegen der virtuellen Funktion automatisch die richtige Funktion aufgerufen wird. Allerdings wird nur Player::generateName aufgerufen.

    Meine Fragen:

    Woran liegt das?
    Muss ich in den Konstruktoren der abgeleiteten Klassen generateName aufrufen (das würde funktionieren ) oder gibt es noch eine andere Methode?

    Hier ist der Code:

    #ifndef _PLAYER_
    #define _PLAYER_
    
    #include <string>
    #include <iostream>
    
    class Player
    {
    public:
           Player()
           {
               name = generateName();
           };
    
           void showName()
           {
    		   std::cout << name << std::endl;
           };
    protected:
              std::string name;
              virtual std::string generateName() = 0;
    };
    
    std::string Player::generateName()
    {
            return "default";
    }
    
    class AIPlayer : public Player
    {
    protected:
              std::string generateName()
              {
                     return Player::generateName();
              };
    };
    
    class HumanPlayer : public Player
    {
    private:
            std::string generateName()
            {
                   //frage Benutzer nach Namen
                   std::string temp;
                   std::cin >> temp;
                   return temp;
            };
    };
    
    #endif
    

    folgendes Testprogramm

    #include <iostream>
    
    #include "Player.h"
    
    void wait();
    
    int main()
    {
    	Player* p1 = new HumanPlayer;
    	Player* p2 = new AIPlayer;
    	p1->showName();
    	p2->showName();
    	wait();
    }
    
    void wait(void)
    {
         std::cin.clear();
         std::cin.ignore(std::cin.rdbuf()->in_avail());
         std::cin.get();
    }
    

    Das Beispiel lässt sich mit VC++ EE problemlos kompilieren, Dev-C++ verweigert jedoch den Aufruf von generateName() in Konstruktor von Player.

    Fehler:
    abstract virtual 'virtual std::string generateName()' called from constructor (Zeile 12)

    Blacker



  • Das ist auch absolut richtig so, da das zu undefiniertem Verhalten führt. Kurzer Artikel gefällig?
    http://www.artima.com/cppsource/nevercall.html



  • was mich auch stutzig macht ist folgendes:

    virtual std::string generateName() = 0;
    };
    
    std::string Player::generateName()
    {
            return "default";
    }
    

    ... zuerst sagst du ... rein virtual ... dann implementierst du aber doch was ^^ also solltest schon ne virtual-Funktion daraus machen ...
    aja und die sollte auch const sein ...



  • Danke, für den Artikel, genau das was ich gesucht hab!

    const hatte ich nur zur Vereinfachung weggelassen.
    Player::generateName() bietet halt ein Standardverhalten an, das die abgeleiteten Klassen aber explicit anfordern müssen. Wäre in diesem Beispiel zwar nicht nötig gewesen, wollt halt nurmal ausprobieren, wie es funktioniert.

    Blacker


Log in to reply