C 中的视觉理解抽象

visual Understanding Abstraction in C++

本文关键字:抽象 视觉      更新时间:2023-10-16

从Java到C ,我正在尝试通过对象取向理解抽象。

为了将其放入一个实用的示例中,我正在使用SFML库来开发一个小型游戏。但是,这个问题与此无关,只需将其视为背景信息即可。无论如何,游戏的工作方式是通过多种不同状态进行处理。在这种情况下2:

  1. 菜单状态:绘制游戏的菜单,游戏将在此处开始。

  2. 游戏状态:此状态控制游戏,将更新实体并绘制它们。

为此,我创建了以下类:

gamestatemanager.h

#ifndef GAMESTATEMANAGER_H
#define GAMESTATEMANAGER_H
#include <SFML/Graphics.hpp>
#include <iostream>
#include "GameState.h"
class GameStateManager
{
public:
    // Constructor
    GameStateManager();
    // State variables
    static const int NUMGAMESTATES = 2;
    static const int MENUSTATE = 0;
    static const int GAMESTATE = 1;
    // Public Functions
    void set_state(int state);
    void update();
    void draw(sf::RenderWindow &win);
    void input(sf::Event event);
private:
    // Array of gamestates
    GameState game_states[];
    // The current state
    int current_state;
    // Private functions
    void load_state(int state);
    void unload_state(int state);
};
#endif

gamestate.h

#ifndef GAMESTATE_H
#define GAMESTATE_H
#include <iostream>
#include <SFML/Graphics.hpp>
#include "GameStateManager.h"
class GameState
{
protected:
    GameStateManager gsm;
public:
    virtual void init() = 0;
    virtual void update() = 0;
    virtual void draw(sf::RenderWindow &win) = 0;
    virtual void input(sf::Event event) = 0;
};
#endif

现在,您可能已经注意到游戏州经理中的游戏阵列吗?这提供了我不理解的错误:零尺寸的数组。这是否意味着需要在标题文件中进行初始化?此外,编译器提到了一个抽象类的数组?

第二个问题是抽象游戏类中的字段GSM无法识别并提出另一个错误:缺少类型的指定词。

现在要使事情变得更复杂,我有以下课程:菜单。该课程旨在扩展游戏。

Menustate.h

#ifndef MENUSTATE_H
#define MENUSTATE_H
#include "GameState.h"
class MenuState: public GameState
{
public:
    MenuState(GameStateManager gsm);
    void init();
    void update();
    void draw(sf::RenderWindow &win);
    void input(sf::Event event);
private:
    sf::Texture title_texture;
    sf::Sprite title_sprite;
};
#endif

如前所述,此类将控制游戏的菜单。

实现gamestateManager如下:

gamestatemanager.cpp

/*
 * GameState Manager will take care of the various states of the game.
 * In particular there will be two states: Menu or Ingame. GameStateManager
 * will load and unload each state as needed.
 *
 * Author: Ben Euden
 * Date: 2/5/2014
 */
#include "GameStateManager.h"
// Class Constructor
GameStateManager::GameStateManager()
{ 
    game_states = game_states[NUMGAMESTATES];
    current_state = MENUSTATE;
    load_state(current_state);
}
/*
 * Load the current game by creating and initialising the state
 * then storing it in the game_states array.
 * @Param state The state we wish to load.
 */
void GameStateManager::load_state(int state)
{
    if(state == MENUSTATE)
        game_states[state] = MenuState(this);
    //if(state == GAMESTATE)
        //game_states[state] = MainGameState(this);    // Not implemented yet.
}
/*
 * Unload the state we loaded with load_state
 */
void GameStateManager::unload_state(int state)
{
    game_states[state] = NULL;
}
void GameStateManager::set_state(int state)
{
    unload_state(state);
    current_state = state;
    load_state(state);
}
void GameStateManager::update()
{
    try{
        game_states[current_state].update();
    }
    catch(int e)
    {
        std::cout << "Exception occured during update of game state" << e << std::endl;
    }
}
void GameStateManager::draw(sf::RenderWindow &win)
{
    try{
        game_states[current_state].draw(&win);
    }
    catch(int e)
    {
        std::cout << "Exception occured when trying to draw gamestate: " << current_state << "Exception number: " << e << std::endl;
    }
}
void GameStateManager::input(sf::Event event)
{
    game_states[current_state].input(event);
}

and菜单如下:

/*
 * This class extends the Game State header and will deal with the menu of the game
 * this includes drawing the correct text to the screen, moving the selector and
 * either exiting, bringing up about or starting the game.
 *
 * Author: Ben Euden
 * Date: 2/5/2014
 */
#include "MenuState.h"

MenuState::MenuState(GameStateManager gsm)
{
    gsm = gsm;
    init();
}
void MenuState::init()
{
    title_texture = sf::Texture();
    title_texture.loadFromFile("sprites/Title.png");
    title_sprite = sf::Sprite();
    title_sprite.setTexture(title_texture);
    title_sprite.setPosition(512, 200);
}
void MenuState::update(){}
void MenuState::draw(sf::RenderWindow &win)
{
    win.draw(title_sprite);
}
void MenuState::input(sf::Event event)
{
}

请忽略成文学的方法和位置。在这一点上,我开始尝试在错误出现时尝试编译项目(我正在使用Visual Studio)。

现在了解到尚未实施Maingamestate,但即使使用壁andate,我敢肯定,我在这里还缺少一些重要的东西,因为我仍在学习C 。考虑到这一点也请原谅任何公约等的违反,我正在学习,所以请随意纠正我,最好现在学习正确的方法,而不是养成不良习惯。

总而言之,我想理解为什么我会收到以下错误:

protected:
    GameStateManager gsm;

这会产生错误:缺少';'GSM之前。

GameState game_states[];

产生以下错误的错误:零大小数组,不允许抽象类的数组。

我相信,如果我修复了其余的,那么

感谢您的耐心,时间和帮助。

euden

简而立即进行项目,并为C 初学者找到一本好书。不要试图混合您的Java知识并填补空白以达到C 知识,它将行不通,因为即使语法接近,它们也是大不相同的野兽。

无论您的背景如何,我总是建议学习C 作为一种新的和不同的语言。现在,您正在做大错误,这表明您走错了学习C 的路径。您应该回到基本教程(我不是要变得苛刻,您确实需要学习基础知识,甚至在设法编译此代码之前)。

您使用数组和成员(例如参考文献)表明您对"价值语义"和其他几个基本概念的理解不足,这些概念是C 用法中必须知道的。

例如,如果我有

class A
{
   int k = 42;  // C++11
};

在这里,一个对象将包含k对象。我的意思是,k不是指向int的指针,而是实际值,在分配到a对象的内存中

所以如果我有

A my_object; // object on the stack

然后 my_object是一个对象,以int的大小。因此,如果我这样做:

class B
{
   int u;
   A a;
};

然后,B的实例实际上是A对象的大小,以及int的大小。b对象将在单个内存中包含所有这些数据。

所以当您这样做时:

class GameState
{
    protected:
    GameStateManager gsm;

您在这里实际做的是,您将完整的GameStateManager构建到任何游戏对象中。是的,GSM不是参考,它是完整的对象。您应该在这里做的是使用C 参考(如果游戏经理永远不会更改)或使用指针(如果涉及所有权,则使用智能POITNER)。

我看到了许多其他问题,例如您的数组成员进入GamestateManager的含义与Java中的含义绝对不相同。基本上,您可以在此处注册C 编码。(并且您应该使用std :: vector或std ::数组,但是您的游戏模式是动态的,所以它会向量或指针数组 - 甚至是映射或其他容器)。

因为有太多要点,我应该到达核心点:

无论您以前学到的语言,甚至与C相关的C或Java,从来没有想过您对C 的了解,您绝对不知道。您需要作为初学者来处理它。将其作为一种非常新的语言学习。

,请确保您实际上阅读了列表所提供的好材料。不幸的是,在网上学习不良练习非常容易(但是它变得更好)。

另外,您可能需要阅读:https://softwareengineering.stackexchange.com/questions/questions/76675/how-can-can-a-a-java-programmer-make-make-make-the-most-the-most-a-most-a-new-project-project-IN-COR-C/76695#76695

顺便说一句,一个相关的建议:阅读" SFML游戏开发"书,例如更简单,更安全(以及C - 惯用)方法来完成您在这里尝试实现的目标。

另一面建议是避免在您的类型名称中使用"管理器",这只会使事情难以理解和设计。

the"零大小数组"错误是由GameState game_states[];引起的。在C 中,您必须在声明时间指定数组大小,要么专门编写大小或直接初始化。

示例:

GameState game_states[ ]; // Error, compiler can't know how much memory to reserve for this.
GameState game_states[4]; // OK, explicit size given, compiler will reserve enough memory for 4 `GameState` objects.
GameState game_states[ ] = { GameState( ), GameState( ) }; // OK, direct initialization, compiler will reserve enough memory for 2 `GameState` object.

在您的情况下应该是:

GameState game_states[ NUMGAMESTATES ];

您应该从GameStateManager构造函数中删除以下行:

game_states = game_states[NUMGAMESTATES]; // Meaningless in C++.

"不允许使用抽象类的数组"此声明也会产生,问题是C 与此处的Java不同。在C 中,此声明一个变量是一个GameState实例,因为GameState具有纯虚拟方法,因此不能实例化(就像Java Abstract类是new ED一样)。为了在C 中实现这种多态性行为,您必须使用指针或参考,这是Java使用的内容。

解决此问题应该给您:

GameState * game_states[ NUMGAMESTATES ];

"缺少';'在GSM发生之前,"仅仅是因为编译器无法编译GameStateManager,请修复我提到的错误应该解决此问题。

几个提示:

  • 将C 中的变量视为Java的int S,即使是您声明自己的类型。这意味着它们仅通过声明然后就实例化(不需要new),并且将它们分配给另一个变量时被复制。(默认为Java没有参考语义)
  • 寻找良好的C 书籍/教程,因为您似乎不了解C 的一些非常重要的基本概念。