我对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 */);
在这种情况下,
keyboardEvents
与SnakeGame
关系不大。实际上,根本没有创建SnakeGame
实例!编译器是正确的,假设chooseMethodFromKeyboardArrows
是direction
,调用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)。