虚拟关键字似乎被忽略了

时间:2016-01-13 00:08:47

标签: c++ inheritance polymorphism

这是我的第一个“大”C ++项目,我被困住了。我正在尝试创建一个简单的ASCII roguelike。我有一个由Player类和Monster类继承的字符类。 Monster类由Vampire和Werewolf类继承。

在GameSystem类的startGame函数中,我将Monsters数组的每个元素(应该用Vampire和Werewolf对象填充)提交给函数moveAround。吸血鬼,狼人和怪兽都有这个功能,但只有Monster moveAround功能正在被访问。如果您在下面的代码中注意到我在Monster类中提供了虚拟关键字。

这让我觉得当我用子类填充Monster数组时我搞砸了。我在GameSystem构造函数中通过随机确定Monster数组的特定元素是狼人还是吸血鬼来做到这一点。

我正在使用代码块,在编译方面,我在g ++之后使用C ++ 11。

GameSystem.cpp

object

GameSystem.h

#include <iostream>
#include <string>
#include "GameSystem.h"
#include "Map.h"
#include "Player.h"
#include "Werewolf.h"
#include "Vampire.h"
#include "conio.h"
#include <cstdio>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>

GameSystem::GameSystem(string mapName){

    srand (time(NULL));

    _map.load(mapName);

    _map.obtainSpawningLocations(_player.getToken(),_player);

    Werewolf werewolf;
    Vampire vampire;

for(int i = 0; i < 5; i++){

    _spawnValue = rand() % 2;   //We generate either 1 or 2

    if(_spawnValue==1){

        _theMonsters[i] = werewolf;
        cout<<"Werewolf"<<endl;
    }
    else{
        _theMonsters[i] = vampire;
        cout<<"Vampire"<<endl;
    }
    _map.obtainSpawningLocations(_theMonsters[i].getToken(),_theMonsters[i]);
}
}
void GameSystem::startGame(){
bool isOver = false;
    while(isOver!=true){

        _map.print();
        movePlayer();
        for(int i = 0; i <5; i++){
        _theMonsters[i].moveAround(); //prints out Monster.moveAround()
        //I need it to print out Vampire.moveAround() and //Werewolf.moveAround

        }

       }
}

void GameSystem::movePlayer(){
    char input;
    input = getch();
    string clearScreenString(100,'\n'); //Prints out a newLine char 100 times
    cout << clearScreenString;
    _map.checkMovement(input, _player);
}


char GameSystem::getch(){

    char buf=0;
    struct termios old={0};
    fflush(stdout);
    if(tcgetattr(0, &old)<0)
        {perror("tcsetattr()");}
    old.c_lflag&=~ICANON;
    old.c_lflag&=~ECHO;
    old.c_cc[VMIN]=1;
    old.c_cc[VTIME]=0;
    if(tcsetattr(0, TCSANOW, &old)<0)
        {perror("tcsetattr ICANON");}
    if(read(0,&buf,1)<0)
        {perror("read()");}
    old.c_lflag|=ICANON;
    old.c_lflag|=ECHO;
    if(tcsetattr(0, TCSADRAIN, &old)<0)
        {perror ("tcsetattr ~ICANON");}
    //printf("%c\n",buf);
    return buf;
 }

Character.cpp

#pragma once
#include "Map.h"
#include <string>
#include <list>

using namespace std;

class GameSystem
{

public:
    GameSystem(string mapName);       //Constructor

    void startGame();    //Start the game
    char getch();
    void movePlayer();

private:

    //int _numberOfMonsters = 5;    //We'll make this a random number later
    Map _map;
    Player _player;
    Monster _monster;
    Monster _theMonsters[5];

    int _x;
    int _y;
    int _spawnValue;
};

Character.h

#include <string>
#include "Character.h"

using namespace std;


Character::Character(){

}


char Character::getToken(){
return _token;
}

void Character::setLocation(int x, int y){
_x = x;
_y = y;
}

void Character::getLocation(int &x, int &y){
x = _x;
y = _y;
}

Map.cpp

#pragma once
#include <string>

class Character{

public:
    Character();

    char getToken();
    void setLocation(int x, int y);
    void getLocation(int &x, int &y);

protected:
    int _x;
    int _y;
    char _token = '!';
};

Map.h

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <cstring>
#include <random>
#include <ctime>
#include <tuple>
#include "Map.h"
#include <time.h>

Map::Map(){
srand (time(NULL));
}

void Map::load(string levelName){
    ifstream theStream;
    theStream.open(levelName);

    if(theStream.fail()){
        perror(levelName.c_str());
        system("PAUSE");
        exit(1);
    }

    string line;
    while(getline(theStream, line)){
    _mapData.push_back(line);
    }
        theStream.close();

}

void Map::obtainSpawningLocations(char characterToken,Character &_character){
/*
Below code provides all the possible spawning locations for the player
and stores them in an array of tuples.
*/

tuple<int,int> myTuple[600];    //Hard coded 600 value is messy.  Change later

int numberOfSpawnPoints = 0;
int upperLimitForNumberGenerator = 0;
/*
The for loop below records all of the possible spawning locations and stores them in the tuple array
*/
    for(int i = 0; i<_mapData.size();i++){
        for(int j = 0; j<_mapData[i].size();j++){
            if(_mapData[i][j]=='.'){
                    get<0>(myTuple[numberOfSpawnPoints]) = j;
                    get<1>(myTuple[numberOfSpawnPoints]) = i;
                    numberOfSpawnPoints++;
                    }
                }
    }
upperLimitForNumberGenerator = numberOfSpawnPoints;

int characterCoordinates = rand()%upperLimitForNumberGenerator;

int xCoordinate = get<0>(myTuple[characterCoordinates]);
int yCoordinate = get<1>(myTuple[characterCoordinates]);

_mapData[yCoordinate][xCoordinate] = characterToken;   //Remember y is first and x is second

_character.setLocation(xCoordinate, yCoordinate);
}

void Map::print(){
    for(int i=0;i<_mapData.size(); i++){
        printf("%s\n", _mapData[i].c_str());
    }
    printf("\n");
}

void Map::checkMovement(char input, Player &aPlayer){ 

int x;
int y;

aPlayer.getLocation(x,y);

char aLocation;

 switch(input) {
    case 'w':
    case 'W':   //If 1 up from the player token is a '.' then we move him up
                //via a different function
                //Otherwise we do nothing.

                aLocation = returnLocation(x,y-1);
                if(aLocation == '.'){
                _mapData[y][x] = '.';
                _mapData[y-1][x] = '@';
                aPlayer.setLocation(x,y-1);
                }
                else
                cout<<"Can't go here!"<<endl;
        break;




    case 'a':
    case 'A':
                aLocation = returnLocation(x-1,y);
                if(aLocation == '.'){
                _mapData[y][x] = '.';
                _mapData[y][x-1] = '@';
                aPlayer.setLocation(x-1,y);
                }
                else
                cout<<"Can't go here!"<<endl;
        break;
    case 's':
    case 'S':

                aLocation = returnLocation(x,y+1);
                if(aLocation == '.'){
                _mapData[y][x] = '.';
                _mapData[y+1][x] = '@';
                aPlayer.setLocation(x,y+1);
                }
                else
                cout<<"Can't go here!"<<endl;
        break;
    case 'd':
    case 'D':
                aLocation = returnLocation(x+1,y);
                if(aLocation == '.'){
                _mapData[y][x] = '.';
                _mapData[y][x+1] = '@';
                aPlayer.setLocation(x+1,y);
                }
                else
                cout<<"Can't go here!"<<endl;






        break;
    default:
        cout<<"Invalid input";
        system("PAUSE");
        break;
    }
}

char Map::returnLocation(int x, int y){
cout<<x<<endl;
cout<<y<<endl;
char aSpot = _mapData[y][x];
return aSpot;

}

Monster.cpp

#pragma once
#include <vector>
#include <fstream>
#include <string>
#include <tuple>
#include <ctime>
#include <random>
#include "Player.h"
#include "Monster.h"

using namespace std;

class Map

{
public:
    Map();      //Constructor
    void load(string levelName);
    void obtainSpawningLocations(char characterToken, Character &aCharacter);
    void checkMovementMonsters(char input, Monster &aMonster);

    //void obtainSpawningLocationsForMonsters(char characterToken, Monster aMonster);

    void print();
    void checkMovement(char input, Player &aPlayer);
    void movement(char characterToken);
    char returnLocation(int x,int y);

   // int numberOfSpawnPoints;

private:
    vector <string> _mapData;
    Player _player;
    Monster _monster;


};

Monster.h

#include <iostream>
#include <string>
#include "Monster.h"

using namespace std;

Monster::Monster(){

}
void Monster::moveAround(){
cout<<"Monster Mash"<<endl;
}

Werewolf.cpp

#pragma once
#include <string>
#include "Character.h"

class Monster: public Character{

public:
    Monster();
    virtual void moveAround();


protected:

    char _token = 'M';
    int _x;
    int _y;
};

Werewolf.h

#include <iostream>
#include <string>
#include "Werewolf.h"

using namespace std;

Werewolf::Werewolf(){

}

void Werewolf::moveAround(){
    cout<<"Werewolf moving around"<<endl;
}

Vampire.cpp

#pragma once
#include <string>
#include "Character.h"      //For inheritance/polymorphism
#include "Monster.h"


class Werewolf: public Monster{
public:
    Werewolf();
    void moveAround();

private:

    char _token = 'W';

};

Vampire.h

#include <iostream>
#include <string>
#include "Vampire.h"

using namespace std;

Vampire::Vampire(){

}

void Vampire::moveAround(){
    cout<<"Vampire moving around"<<endl;
}

Player.cpp

#pragma once
#include <string>
#include "Character.h"      //For inheritance/polymorphism
#include "Monster.h"


class Vampire: public Monster{
public:
    Vampire();
    virtual void moveAround();

private:

    char _token = 'V';

};

Player.h

Player::Player(){

}

主要

#pragma once
#include <string>
#include "Character.h"
using namespace std;

class Player : public Character {

public:
    Player();  

protected:
    int _x;
    int _y;
    char _token = '@';
};

级别文本文件:

#include <iostream>
#include "GameSystem.h"
using namespace std;

int main()
{
GameSystem gameSystem("LevelOne.txt");
gameSystem.startGame();
    return 0;
}

2 个答案:

答案 0 :(得分:1)

_theMonsters [i] .moveAround()上没有发生虚拟调度。你需要有一个指向怪物类型对象的数组。实际上,在尝试设置类层次结构的方式中存在一些问题,例如,在派生类中具有相同名称的成员变量。

答案 1 :(得分:1)

这里有几个问题。

  1. Monster::_tokenWerewolf::_tokenVampire::_token都是不同的变量。 Werewolf对象同时包含Monster::_tokenWerewolf::_token
  2. Monster _theMonsters[5]是一个包含5个Monster个对象的数组。它永远不会是VampireWerewolf,始终是Monster。由于对象始终是相同的类型,因此不会进行虚拟调度:Monster
  3. 虚拟调度仅适用于指针和引用。要使其工作,您需要使用指向Monster的指针数组:Monster* _theMonsters[5]。然后你可以像_theMonsters[i] = new Vampire()一样填写它。如果你这样做,你需要记住delete对象完成后,或者你可以使用智能指针,如std::unique_ptrstd::shared_ptr而不是raw { {1}}秒。