c++ - 虚拟关键字似乎被忽略

标签 c++ inheritance polymorphism

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

在 GameSystem 类的 startGame 函数中,我将 Monsters 数组(应该填充 Vampire 和 Werewolf 对象)的每个元素提交给函数 moveAround。 Vampires、Werewolfs 和 Monsters 都有这个函数,但只有 Monster moveAround 函数被访问。如果您在下面的代码中注意到我在 Monster 类中提供了 virtual 关键字。

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

我正在使用代码块,并且在编译方面我有遵循 C++11 的 g++。

游戏系统.cpp

#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;
 }

游戏系统.h

#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;
};

角色.cpp

#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;
}

字符.h

#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 .cpp

#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;

}

map .h

#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;


};

怪物.cpp

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

using namespace std;

Monster::Monster(){

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

怪物.h

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

class Monster: public Character{

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


protected:

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

狼人杀.cpp

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

using namespace std;

Werewolf::Werewolf(){

}

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

狼人杀

#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';

};

吸血鬼.cpp

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

using namespace std;

Vampire::Vampire(){

}

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

吸血鬼.h

#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';

};

播放器.cpp

Player::Player(){

}

播放器.h

#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;
}

关卡文本文件:

############################################
#..........................................#
#..........................................#
#...........................^..............#
#..........................................#
#......................#...................#
#......................#...................#
#......................#...................#
#............^.........#...................#
#......######..........#..&................#
#......\...............#...................#
#......................#...................#
#..........................................#
#..........................................#
############################################

最佳答案

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

关于c++ - 虚拟关键字似乎被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34756163/

相关文章:

c++ - 私有(private)成员的继承

java - child 没有继承其 parent 的一些属性/行为?

c++ - 为什么在 32 位 ARM 平台上 SIGSEGV 的故障地址是 0x00000006?

c++ - 使用指针对象的 std::vector。当 vector 超出范围时,有没有办法从 vector 中删除该项目?

c++ - 在opencv中发现凸性缺陷? [崩溃取决于给定的输入图像..]

python - 覆盖 __dir__ 方法的正确方法是什么?

function - 两个相似的函数如何在 Haskell 中具有不同的多态类型?

c++ - 减少重载函数和构造函数的数量

java - 如何使扩展对象转向其超对象

c++ - 如何将对 Winform 成员函数的引用传递给不同线程的不同类?