我对typename SnakeGame有问题。我想知道如何在SnakeGame类中使KeyboardEvents成为全局类型。现在像DirectionKeyboard这样的嵌套类不知道SnakeGame是什么类型,因为它只能看到see KeyboardEvents<SnakeGame>类型。我不知道如何更改它:P

这是错误:

不知道参数1从'KeyboardEvents SnakeGame>&'到'SnakeGame&'的转换

我非常感谢您的帮助。

keyboardEvents.hpp

#include<SFML/Graphics.hpp>

template <typename SnakeGame>
class KeyboardEvents {
public:
    virtual ~KeyboardEvents() = default;

protected:
    class DirectionKeyboardEvent{
    public:
        virtual ~DirectionKeyboardEvent() = default;
        virtual void direction(SnakeGame&) = 0; // error no know conversion
    };

    class GoRight : public DirectionKeyboardEvent {
    public:
        void direction(SnakeGame& snakeObj) {
            snakeObj.snake[0].xCoor+=1;
        }
    };

    class GoRight : public DirectionKeyboardEvent {
    public:
        void direction(SnakeGame& snakeObj){
            snakeObj.snake[0].xCoor += 1;
        }
    };

    class GoLeft : public DirectionKeyboardEvent{
    public:
        void direction(SnakeGame& snakeObj){
            snakeObj.snake[0].xCoor-=1;
        }
    };

    class GoUp:public DirectionKeyboardEvent{
    public:
        void direction(SnakeGame& snakeObj){
            snakeObj.snake[0].yCoor-=1;
        }
    };

    class GoDown : public DirectionKeyboardEvent{
    public:
        void direction(SnakeGame& snakeObj){
            snakeObj.snake[0].yCoor+=1;
        }
    };

    std::map<sf::Keyboard::Key,  std::shared_ptr<DirectionKeyboardEvent>> mapOfDirects;

    void initializeDirectionMap() {
        mapOfDirects[sf::Keyboard::Right] = std::shared_ptr< DirectionKeyboardEvent >(new GoRight);
        mapOfDirects[sf::Keyboard::Left] = std::shared_ptr<DirectionKeyboardEvent>(new GoLeft);
        mapOfDirects[sf::Keyboard::Up] = std::shared_ptr<DirectionKeyboardEvent>(new GoUp);
        mapOfDirects[sf::Keyboard::Down] = std::shared_ptr<DirectionKeyboardEvent>(new GoDown);
    }

    void chooseMethodFromKeyboardArrows(sf::Keyboard::Key codeFromKeyboard) {
        auto iterator = mapOfDirects.find(codeFromKeyboard);

        if(iterator!=mapOfDirects.end()){
            iterator->second->direction(*this);//left , right,up , down, pause
            mainDirection=codeFromKeyboard;
        } else {
            mapOfDirects[mainDirection]->direction(*this);
        }
    }
};

这是我使用KeyboardEvents〜snakeGame.hpp的类
#include"keyboardEvents.hpp"

class SnakeGame:public Screen, public KeyboardEvents<SnakeGame> {
    public:
        SnakeGame(int size=16, int width=15, int height=15, int timeDelay=60000)
            : Screen(size, width, height), KeyboardEvents<SnakeGame>(), timeDelay(timeDelay) {}
};

最佳答案

在尝试调用DirectionKeyboardEvent::direction类内的KeyboardEvents时。

即使您放置的模板参数恰好是子类,编译器也无法提前知道KeyboardEvents<SnakeGame>将被SnakeGame类绝对扩展。

我的意思是,可以编写以下代码:

KeyboardEvents<SnakeGame> keyboardEvents;

keyboardEvents.chooseMethodFromKeyboardArrows(/* some key */);

在这种情况下,keyboardEventsSnakeGame关系不大。实际上,根本没有创建SnakeGame实例!编译器是正确的,假设chooseMethodFromKeyboardArrowsdirection,调用KeyboardEvents<SnakeGame>的函数SnakeGame是错误的。

继承的工作方式相反:SnakeGame确实是KeyboardEvents<SnakeGame>。另一种方法是错误的。

我可以向您展示如何“使其工作”,但是这里需要警告:您过度使用了继承,在KeyboardEvent的情况下使用了错误的方式。您确实应该尝试重新安排周围的事情,否则最终将陷入困惑。

解决方案“使其起作用”

由于您使用的是CRTP,因此可以告诉编译器,在所有情况下KeyboardEvents<SnakeGame>实际上都是由SnakeGame扩展的。如果确实如此,您可以将基类static_cast编码为子类:
if(iterator!=mapOfDirects.end()){
    // Notice the presence of the cast here
    iterator->second->direction(static_cast<SnakeGame&>(*this));
    mainDirection=codeFromKeyboard;
}

稍微好一点的解决方案

您也可以将蛇类的现有实例用作参数。
void chooseMethodFromKeyboardArrows(sf::Keyboard::Key codeFromKeyboard, SakeGame& game){
    auto iterator = mapOfDirects.find(codeFromKeyboard);

    if(iterator!=mapOfDirects.end()){
        iterator->second->direction(game);
        mainDirection=codeFromKeyboard;
    } else {
        mapOfDirects[mainDirection]->direction(game);
    }
}

但是,最好的主意是不要使SnakeGame扩展KeyboardEvent,而应将其包含在类中:
struct SnakeGame : Screen {
    KeyboardEvent<SnakeGame> event;

    void callEvents() {
        event.chooseMethodFromKeyboardArrows(/* some key */, *this);
    }
};

这是为您准备的作业:
尝试使KeyboardEvent类不是模板。我敢肯定,您可以找到一种无需使用模板就可以传递您的类的方法,同时仍然可以直接访问类SnakeGame,而无需强制转换或接口(interface)。

10-08 07:15