C++ 模板类和嵌套类C++;
我对C++ 模板类和嵌套类C++;,c++,templates,inner-classes,C++,Templates,Inner Classes,我对typename SnakeGame有问题。我想知道如何在classKeyboardEvents中将SnakeGame制作成全局类型。现在,像DirectionKeyboard这样的嵌套类不知道蛇游戏的类型是什么,因为它只看到seeKeyboardEventstype。我不知道如何改变它:P 以下是错误: 未知参数1从“KeyboardEvents SnakeGame>&”到“SnakeGame&”的转换 我非常感谢你的帮助 keyboardEvents.hpp #include<SF
typename SnakeGame
有问题。我想知道如何在classKeyboardEvents
中将SnakeGame
制作成全局类型。现在,像DirectionKeyboard
这样的嵌套类不知道蛇游戏的类型是什么,因为它只看到seeKeyboardEvents
type。我不知道如何改变它: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);
}
}
};
你的设计似乎有点过于复杂了。我认为这样做的原因可能是你在设计它的过程中。有时,坐下来先考虑这些事情会有帮助,如果有必要,可以在白板上画框和线 无论如何,这并不是对你问题的直接回答,而是基于我猜你正在尝试做的事情而提出的一个替代建议 在我看来,您正在尝试实现一些通用键盘输入处理程序,并将其绑定到您的游戏中。这可能是我完全错了,但是如果不是,考虑这样的事情。首先,一个通用接口,用于接收键盘事件。它不需要是一个模板,这并不是一个很好的模板用例:
class KeyboardEventHandler {
public:
enum Direction { Left, Right, Up, Down };
virtual ~KeyboardEventHandler () { }
virtual void onDirectionKey (Direction d) = 0;
};
现在,处理键盘事件的SnakeGame
,可以继承并实现自己的SnakeGame
特定逻辑:
class SnakeGame : public KeyboardEventHandler {
public:
void onDirectionKey (Direction d) {
switch (d) {
case Up: ...
case Down: ...
case Left: ...
case Right: ...
}
}
};
然后,不管你有多少代码来处理键盘事件并驱动所有这些,都可以使用KeyboardEventHandler*
,这可能是一个蛇形游戏,也可能是你将来决定使用它的任何东西
这只是组织的一种可能性。例如,您可以这样构造它,分解KeyboardEvent
,这可以简化将来的添加:
class KeyboardEvent {
public:
enum Direction { Left, Right, Up, Down };
Direction getDirection () { ... } // or whatever
};
class KeyboardEventHandler {
public:
virtual ~KeyboardEventHandler () { }
virtual void onEvent (KeyboardEvent &event) = 0;
};
使用蛇类游戏
作为:
class SnakeGame : public KeyboardEventHandler {
public:
void onEvent (KeyboardEvent &event) {
...
}
};
如果您愿意,您可以将这些内容命名为除方向之外的其他内容,我从您的示例中选择了它,但只需将其命名为语义上适当且方便的内容(例如,如果您计划将其扩展为包含箭头以外的内容)。但不管怎样,这都不是重点
除此之外,还有10多种其他方法可以剥下这只猫的皮,但重要的一点是:如果你试图为某些东西创建一些通用接口,你真的不能让它依赖于继承它的特定细节,否则你就无法从一开始就将其通用化。在这种情况下,要么它不是通用基/继承的好例子,要么你只是把设计搞砸了,需要坐下来重新思考
请记住:您的目标不是向代码中添加尽可能多的类和内容;你不会想要遗产的高分。您的目标是保持代码干净、可读、可维护、正确、可能可重用,并使您的工作更轻松。这些都是工具,不要因为你拥有它们就使用它们,而是在你需要它们的时候使用它们,让你的生活更轻松
不过,尽管这是一个有趣的练习,但对于您的特定应用程序来说,这仍然是多余的。老实说,在您的特定情况下,我只想放弃所有继承等,然后做如下操作:
class SnakeGame {
public:
void handleKeyPress (char c) {
// ... do the right thing here
}
}
然后完成它。在您的中,尝试调用KeyboardEvents
类中的DirectionKeyboardEvent::direction
即使您放置了一个恰好是子类的模板参数,编译器也无法预先知道KeyboardEvents
将绝对由类SnakeGame
扩展
我的意思是,人们可以编写以下代码:
KeyboardEvents<SnakeGame> keyboardEvents;
keyboardEvents.chooseMethodFromKeyboardArrows(/* some key */);
稍微好一点的解决方案
您还可以使用snake类的现有实例作为参数
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);
}
}
但是,最好的办法是不要使蛇形游戏
扩展键盘事件
,而是将其包含在类中:
struct SnakeGame : Screen {
KeyboardEvent<SnakeGame> event;
void callEvents() {
event.chooseMethodFromKeyboardArrows(/* some key */, *this);
}
};
结构蛇游戏:屏幕{
键盘事件;
void callEvents(){
事件。从键盘箭头(/*某些键*/,*此键)选择方法;
}
};
这是给你的家庭作业:
尝试使类
KeyboardEvent
不是模板。我相信您可以找到一种方法,在不使用图版的情况下,在不使用强制类型或接口的情况下,直接访问类SnakeGame
。您可以拥有一个iner成员SnakeGame s
,然后检查is类型。SnakeGame
是一个类,我想在KeyboardEvents
类中更改该类的成员。由于这个原因,SnakeGame
是模板,我通过引用方向函数传递SnakeGame
对象。你为什么需要知道SnakeGame
的真实身份?我没有其他想法:P我在一个文件中有SnakeGame
和KeyboardEvents
,但我想重构这个代码,我推了KeyboardEvents
到KeyboardEvents.hpp
file;)。这些似乎试图过度概括您的设计。如果您的KeyboardEvents类直接插入SnakeGame的成员,那么您将无法使用SnakeGame以外的任何类型,这使得这对于模板来说是一个糟糕的用例。非常感谢!我做了KeyboardEvents
等,因为我已经开始学习面向对象编程,我会训练一些关于蛇游戏的方法。例如,我去掉了ifs
和switch
,并将所有状态转移到类中。当我在SnakeGame
课程中学习KeyboardEvents
时,一切都很好。但当我的程序越来越大时,我决定将KeyboardEvents
类转移到另一个文件,然后我就一直在努力解决这个问题。我知道这一切都结束了
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);
}
}
struct SnakeGame : Screen {
KeyboardEvent<SnakeGame> event;
void callEvents() {
event.chooseMethodFromKeyboardArrows(/* some key */, *this);
}
};