Thread: Plymorphism again!!!

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    25

    Plymorphism again!!!

    I have a base class with a virtual function that i define within the base class as well as the derived class in main I have the following code:

    Code:
    int main()
    {
      Player *A  =  &Human class;  //Human is derived from Player
      Player *B =  &Computer class;  //Computer is derived from Player
    
    A->Attack();
    B->Attack();
    
    return 0;
    
    }
    Attack() is the function I define in all three classes how do I get it to call the function in the class it references.

  2. #2
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Well, you make a base class with a virtual function that you define within the base class as well as in the derived class. Have you done that?

  3. #3
    Registered User
    Join Date
    Nov 2006
    Posts
    25
    yes I did that and when I call the functions It only calls the base class definitions

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Show the class definitions.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    Nov 2006
    Posts
    25
    Here are the implementations I know I am doing something dumb somebody please point it out

    Code:
    //Player Class
    
    //******************************************************************
    //Function     : Constructor
    //PreCondition : a valid file name
    //PostCondition: Board object is created and file is open
    //******************************************************************
    
    Player::Player(const string& File) : PlayerBoard(File)
    {}
    
    //******************************************************************
    //Function     : Retrieves Board Object
    //PreCondition : None
    //PostCondition: Board Object is returned
    //******************************************************************
    
    Board Player::GetBoard()const
    {return PlayerBoard;}
    
    
    //******************************************************************
    //Function     : intializes players board with a game board
    //Precondition : Not attempting a self copy
    //Postcondition: Players board is now filed with a certain amount of
    //               ships and ready for battle 
    //******************************************************************
    
    
    void Player::SetBoard()
    {
      cin>>PlayerBoard;
    }
    //******************************************************************
    //Function     : Records the result of Opponent attacks
    //PreCondition : None
    //PostCondition: Result is stored on Players Board
    //******************************************************************
    
    void Player::Attack(const int& row, const int& column)
    {   
      PlayerBoard.RecordAttack(row, column);
    }
    
    
    bool Player::CheckForHitMiss(const int& row, const int& col)
    {
      bool boolean = PlayerBoard.I........OrMiss(row,col);
      return boolean;
    }
    
    
    bool Player::CheckForHit(const int& row, const int& col)
    {
      bool boolean = PlayerBoard.I........(row,col);
      return boolean;
    }
    
    const int Player::GetCounter()const
    {
      return (PlayerBoard.GetCounter());
    }
    //******************************************************************
    //Function     : Prints Player Board to the screen
    //PreCondition : None
    //PostCondition: Board is outputted to the screen
    //******************************************************************
    
    ostream& operator<<(ostream& out, const Player& APlayer)
    {
      out<<APlayer.PlayerBoard;
      return out;
    }
    
    
    //******************************************************************
    //Function     :Inputs from a file to the board object
    //PreCondition :valid file name and file can be read
    //PostCondition:Input from file is stored into the board
    //******************************************************************
    
    istream& operator>>(istream& in, Player& APlayer)
    {
      in>>APlayer.PlayerBoard;
      return in;
    }
    //Human.cpp
    Code:
    
    //**********************************************************
    //Function: Constructor
    //PreCondition: Valid file name
    //PostCondition: A board object is created
    //**********************************************************
    
    Human::Human(const string name) : Player(name)
    {
    }
    
    //**********************************************************
    //Function: acquires attack points from user and process
    //the points unto opponents board
    //PreCondition:points are valid points on the board
    //PostCondition:at attack point
    //**********************************************************
    
    void Human::Attack(int row, int column)
    {
      cout<<"I am attempting to attack the board"<<endl;
    
      Player::Attack(row,column);
    }
    
    //**********************************************************
    //Function: gets number of attack points
    //PreCondition: None
    //PostCondition:number of attack points is sent to function
    //caller.
    //**********************************************************
    
    
    const int Human::GetCounter()const
    {
      return Player::GetCounter();
    }
    
    
    //******************************************************************
    //Function     : Checks for hit or a miss
    //PreCondition : none
    //PostCondition: returns true if the square contains a hit or miss
    //******************************************************************
    
    bool Human::CheckForHitMiss(const int& row, const int& col) 
    {
      return (Player::CheckForHitMiss(row,col));
     
    }
    
    //******************************************************************
    //Function     : Checks whether attack points have a hit on it
    //PreCondition : none
    //PostCondition: true is returned if it was a hit and false if not
    //******************************************************************
    
    
    bool Human::CheckForHit(const int& row, const int& col)
    {
      return (Player::CheckForHit(row,col));
     
    }
    
    
    
    //********************************************************************
    //Function      : Retrieves attack points from user
    //PreCondition  :input from user,row and column, is correct
    //PostCondition : attack points are store for later retrieval
    //********************************************************************
    
    
    void Human::GetAttckPnts()
    {
      char user_row;
      string garbage;
      bool control;
    
      while(control == false)
        {
         cout<<endl<< "Please enter where you would like to attack (row column) (ex: A 1): ";
         cin>>user_row;
         cin>>m_col;
         cout<<endl<<endl;
         char c;
    
         //make sure input was no more than two characters
    
         c =cin.peek();
    
         if( c != '\n'){
          cout<<"Only the first two characters have been accepted as attack points!!!"<<endl;
          cin>>garbage;
         }
    
         //change input to integers
    
         SwitchFunc(user_row);
     
         if((m_row == -1) || (m_col < 0) || (m_col > 9))
          {
            cerr<<"Invalid Input Please Re-enter: "<<endl;
    	control = false;
          }
         else
          control = true;
        }
     
    }
    
    //********************************************************************
    //Function      :Switches char row value to integer
    //PreCondition  :valid input is entered
    //PostCondition :integer form of row is entered
    //********************************************************************
    
    
    void Human::SwitchFunc(const char& user_row)
     {
       switch ( user_row ) {
       case 'A':
         m_row = 0;
         break;
       case 'B':
         m_row = 1;
         break;
       case 'C':
         m_row = 2;
         break;
       case 'D':
         m_row = 3;
         break;
       case 'E':
         m_row = 4;
         break;
       case 'F':
         m_row = 5;
         break;
       case 'G':
         m_row = 6;
         break;
       case 'H':
         m_row = 7;
         break;
       case 'I':
         m_row = 8;
         break;
       case 'J':
         m_row = 9;
         break;
       default:
         m_row = -1;
         break;
       }
    }
    
    //**********************************************************
    //Function     : gets row value of board
    //PreCondition : none
    //PostCondition: row value is returned
    //**********************************************************
      
    const int Human::GetRow()const
    {return m_row;}
    
    
    //**********************************************************
    //Function     : gets column value of board 
    //PreCondition : none
    //PostCondition: col value is returned
    //**********************************************************
    
    const int Human::GetCol()const
    {return m_col;}
    
    
    
    //**********************************************************
    //Function     : Prints Human Player board to the screen
    //PreCondition : None
    //PostCondition: Human Board is sent to the screen with
    //               updated attacks.
    //**********************************************************
    
    
    ostream& operator<<(ostream& out, const Human& Human)
    {
      out<<Human.Player::GetBoard();
      return out;
    }
    
    
    //**********************************************************
    //Function: Read Board into vector
    //PreCondition: Valid file name
    //PostCondition: Human board is read into a vector through
    //a board object
    //**********************************************************
    
    
    istream &operator>> (istream& in, Human& Human)
    {
      Human.Player::SetBoard();
      return in;
    }
    //Computer

    Code:
    //**********************************************************
    //Function: Constructor
    //PreCondition: Valid file name
    //PostCondition: A board object is created
    //**********************************************************
    
    
    Computer::Computer(const string& name) : Player(name)
    {
      m_row= m_col = 0;
      AttackPoints = new Queue;
    }
    
    //*********************************************************
    //Function     : Destructor
    //PreCondition : Queue is not empty
    //PostCondition: all objects are destroyed
    //*********************************************************
    
    
    Computer::~Computer() 
    {
      delete AttackPoints;
    }
    
    
    //********************************************************************
    //Function      : Retrieves attack points either randomly or from a queue
    //PreCondition  : Queue is not empty
    //PostCondition : Attack points are either retrieve randomly(if queue is 
    //                empty) or from the queue, points are stored for later
    //                retrieval
    //********************************************************************
    
    
    void Computer::GetAttckPnts()
    {
      char alpha_row;
      Square BoardSquare;
      
    
      //if queue of board squares is empty randomly select a square to attack
      if((*AttackPoints).IsEmpty())
        {
          srand(time(NULL));
          m_row= Generator();
          m_col = Generator();
          if (m_row== 0)
           alpha_row= 'A';
          if (m_row== 1)
           alpha_row= 'B';
          if (m_row== 2)
           alpha_row= 'C';
          if (m_row== 3)
           alpha_row= 'D';
          if (m_row== 4)
           alpha_row= 'E';
          if (m_row== 5)
           alpha_row= 'F';
          if (m_row== 6)
           alpha_row= 'G';
          if (m_row== 7)
           alpha_row= 'H';
          if (m_row== 8)
           alpha_row= 'I';
          if (m_row== 9)
           alpha_row= 'J';
     
          
          cout<<endl<<"Computer has choosen to attack: ("<<alpha_row<<","<<m_col<<")"<<endl;
    
       
        }//end of if
    
       else{
         //retrieve a board square from the queue
        BoardSquare = (*AttackPoints).Front();
       
        //retrieve row and column numbers of the square
        m_row = BoardSquare.GetRow();
        m_col = BoardSquare.GetCol();
    
        SrchForAttckPnts();
    
       }//end of else
    
    }//end of GetAttckPnts 
     
    
    
    //*********************************************************
    //Function     : Searches Queue for valid attack points
    //PreCondition : Queue is not empty
    //PostCondition: invalid attack points are removed till a 
    //               valid one is retrieved, valid points coordinates
    //               are stored for retrieval
    //*********************************************************
    
    
    void Computer::SrchForAttckPnts()
    {
      char alpha_row;
      Square BoardSquare;
    
      bool CheckAttack = CheckForHitMiss(m_row, m_col);
    
      //while the square is not empty search for a square not attacked yet or 
      //retrieve the square and attack it
    
    
      while(!(*AttackPoints).IsEmpty())
       {
         if(CheckAttack == true)
           {
            (*AttackPoints).Dequeue();
            BoardSquare = (*AttackPoints).Front();
            m_row = BoardSquare.GetRow();
            m_col = BoardSquare.GetCol();
    
    	CheckAttack = CheckForHitMiss(m_row,m_col);
       }//end of inner if
         else
          break;
       }//end of while
    
       if (m_row == 0)
        alpha_row = 'A';
       if (m_row == 1)
        alpha_row = 'B';
       if (m_row == 2)
        alpha_row = 'C';
       if (m_row == 3)
        alpha_row = 'D';
       if (m_row == 4)
        alpha_row = 'E';
       if (m_row == 5)
        alpha_row = 'F';
       if (m_row == 6)
        alpha_row = 'G';
       if (m_row == 7)
        alpha_row = 'H';
       if (m_row == 8)
        alpha_row = 'I';
       if (m_row == 9)
        alpha_row = 'J';
    
       cout<<endl<<"Computer has choosen to attack: ("<<alpha_row<<","<<m_col<<")"<<endl;
    
       //remove square from queue
       (*AttackPoints).Dequeue();
    
    }//end of SrchForAttckPnts
    
    
    //*********************************************************
    //Function     : Stores attack points in a queue
    //PreCondition : None
    //PostCondition: attack points are stored into the queue
    //*********************************************************
    
    
    void Computer::EnqueueAttckPnts(int row, int col)
    {
      cout<<"enqueing points"<<endl;
      //enqueue surrounding squares around the square(row,col)
       (*AttackPoints).Enqueue((row-1),col);
       (*AttackPoints).Enqueue(row,(col+1));
       (*AttackPoints).Enqueue((row+1),col);
       (*AttackPoints).Enqueue(row,(col-1));
    
     
    }
    
    //******************************************************************
    //Function     : Checks for hit or a miss
    //PreCondition : none
    //PostCondition: returns true if the square contains a hit or miss
    //******************************************************************
    
    bool Computer::CheckForHitMiss(const int& row, const int& col)
    {
      return (Player::CheckForHitMiss(row,col));
     
    }
    
    //******************************************************************
    //Function     : Checks whether attack points have a hit on it
    //PreCondition : none
    //PostCondition: true is returned if it was a hit and false if not
    //******************************************************************
    
    
    bool Computer::CheckForHit(const int& row, const int& col)
    {
      return (Player::CheckForHit(row,col));
     
    }
    
    
    //**********************************************************
    //Function: acquires attack points from queue and process
    //the points unto opponents board
    //PreCondition:points are valid points on the board
    //PostCondition:a H or M is stored at attack point.
    //              H is for Hit, M is for Miss
    //**********************************************************
    
    
    
    void Computer::Attack(const int row, const int col)
    {
      cout<<"in attack"<<endl;
    
      Player::Attack(row, col);
      
      bool boolean;
    
      boolean = CheckForHit(row,col);
    
       if (boolean == true)
        EnqueueAttckPnts(row,col);
    }
    
    
    
    //**********************************************************
    //Function: gets number of attack points
    //PreCondition: None
    //PostCondition:number of attack points is sent to function
    //caller.
    //**********************************************************
    
    
    const int Computer::GetCounter()const
    {
      return Player::GetCounter();
    }
    
    
    //********************************************************************
    //Function      :Random number generator
    //PreCondition  :None
    //PostCondition :A number between 0 and 9 is generated
    //********************************************************************
    
    
    const int Computer::Generator()
    {
     
      const int num = rand()%10;
      return num;
    }
    
    //******************************************************************
    //Function     : Gets row of attack points
    //PreCondition : none
    //PostCondition: row value is returned
    //******************************************************************
    
    
    const int Computer::GetRow()const
    {return m_row;}
    
    
    //******************************************************************
    //Function     : Gets column of attack points
    //PreCondition : none
    //PostCondition: column value is returned
    //******************************************************************
    
    
    const int Computer::GetCol()const
    {return m_col;}
    
    
    //**********************************************************
    //Function     :Prints Computer Board to the screen
    //PreCondition :None
    //PostCondition:Opponents updated attacks are outputted to
    //              to the screen
    //**********************************************************
    
    
    ostream &operator<<(ostream &out, const Computer &Comp)
    {
      out<<Comp.Player::GetBoard();
      return out;
    }
    
    
    
    //**********************************************************
    //Function: Read Board into vector
    //PreCondition: Valid file name
    //PostCondition: Computer board is read into a vector
    //through a board object
    //**********************************************************
    
    
    istream& operator>> (istream &in, Computer &Comp)
    {
      Comp.Player::SetBoard();
      return in;
    }

  6. #6
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    You are defining A and B as being of type pointer to base class. That is why only the base class virtual function are being called.

    You should define A and B as being of the derived types. Dynamic binding will do the rest for you.

    EDIT: From skimming your code, there won't be any dynamic binding. However, you still need to define your objects of the derived types for the correct function to be called. Let us know if you need any help in understanding dynamic binding and polymorphism.
    Last edited by Mario F.; 11-23-2006 at 06:52 PM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  7. #7
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    You are defining A and B as being of type pointer to base class. That is why only the base class virtual function are being called.

    You should define A and B as being of the derived types. Dynamic binding will do the rest for you.
    What? A is of the type Base *, but it points to a Derived. Dynamic binding should occur, and the types of A and B should not have to change.

    That code that you provided doesn't help much. If the declarations (stuff in the header files) of the classes bear any resemblance to

    Code:
    class player { virtual void attack(); };
    class human : public player { [virtual] void attack(); };
    class computer : public player { [virtual] void attack(); };
    Then dynamic binding should occur how it is. Also granted that your code has something more semantically correct than.

    Code:
      Player *A  =  &Human class;  //Human is derived from Player
      Player *B =  &Computer class;  //Computer is derived from Player
    >> From skimming your code, there won't be any dynamic binding.

    I don't see how you determined that.
    Last edited by Tonto; 11-23-2006 at 07:07 PM.

  8. #8
    Registered User
    Join Date
    Nov 2006
    Posts
    25
    I do have the declarations virtual attack() in all three header files and when i instantiate the objects
    I have
    Code:
    Player1 = &HumanObject;
    Player2 = &ComputerObject;
    
    Player1.attack();
    Player2.attack();
    and both functions go directly to the base function attack. I have cout statements within each attack function to see the hierachy and I only see the base function cout statements. I get no dynamic binding. So maybe I need a little help with the semantically correct part please!!!!

  9. #9
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Code:
    int main()
    {
          Player * player1 = &humanobject;
          Player * player2 = &computerobject;
    
          player1->attack();
          player2->attack();
    }
    Or using references

    Code:
    int main()
    {
            Player & player1 = humanobject;
            Player & player2 = computerobject;
    
            player1.attack();
            player2.attack();
    }
    Just do not do

    Code:
    int main
    {
            Player player1 = humanobject;
            Player player2 = computerobject;
    
            player1.attack();
            player2.attack();
    }
    P.S. That's not a matter of semantics, just what you had in your original post isn't something that would compile.
    Last edited by Tonto; 11-23-2006 at 07:19 PM.

  10. #10
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Yes. I should have payed more attention to the declarations. Sorry about that.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  11. #11
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    > I get no dynamic binding.

    How are humanobject and computerobject being declared?
    Are your Human and Computer leaf classes deriving from Player?
    Are the virtual attack() functions being declared exactly with the same name and parameters in all classes?

    EDIT: Nevermind... The answer to the third question is no. And that is why you are not getting dynamic binding. You have to declare them the same on each class.
    Last edited by Mario F.; 11-23-2006 at 07:29 PM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  12. #12
    Registered User
    Join Date
    Nov 2006
    Posts
    25
    thanks I had that already but let me show u my main
    Code:
      
    void BeginGame(string f1, string f2, string _Player)
    {
      
      Human HumanPlayer(f2);
      Player* Player1 = &HumanPlayer;
      Computer ComputerPlayer(f1);
      Player* Player2 = &ComputerPlayer;
    
      int counter;
      cin>>(*Player1);
      cin>>(*Player2);
    
    
      while(_Player != "defeated")
        {
          if(_Player == "COMP"){
             Attack(Player2);
    	 counter = Player1->GetCounter();
    	 if (counter == 1)
    	   _Player = "defeated";
    	 else
    	  _Player = "HUMAN";
          } 
          else if(_Player == "HUMAN"){
    	Attack(Player1);
    	counter = Player2->GetCounter();
    	if (counter == 1)
    	  _Player = "defeated";
    	else
    	  _Player = "COMP";
          }
             else{
              cerr<<"Invaid argument:  Program is exiting";
              exit(1);
             }
        }
    
      counter = Player1->GetCounter();
    
      if(counter  == 1)
        cout<<"Computer has won"<<endl;
      else
        cout<<"You have won"<<endl;
      
     
      cout<<endl<<endl;
      cout<<"***************  THANKS FOR PLAYING BATTLESHIP***************"<<endl<<endl;
    
    
      // delete Player1;
      // delete Player2;
    }
    
    
    void Attack(Player* PlayerA)
    {
      bool Check;
      int row, column;
      string control;
    
      PlayerA->GetAttckPnts();
    
      row = PlayerA->GetRow();
      column = PlayerA->GetCol();
    
      PlayerA->Attack(row, column);
    
      cout<<(*PlayerA)<<endl;
    
    }
    maybe there is something there that i missed

  13. #13
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Post the declarations, e.g. just the header files.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  14. #14
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Just read my previous post. This is how you are declaring Attack()

    Code:
    void Player::Attack(const int&, const int&);
    void Human::Attack(int, int);
    void Computer::Attack(const int, const int)
    Your function declarations must match Player::Attack. They all have to be the same.

    My bet is that since they don't, you don't get dynamic binding. Since you don't get dynamic binding, it is the static type of your object that will be used to locate Attack(). The static type is Player*. The base class.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  15. #15
    Registered User
    Join Date
    Nov 2006
    Posts
    25

    Talking

    I knew I was doing something wrong I really thought I had them declared the same thanks for being my eyes because they are so tired of looking at this code. Thank You, u don't know how much I appreciate all of your help.

    THANKS !!!!!!!!!

Popular pages Recent additions subscribe to a feed