Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板类和嵌套类C++;_C++_Templates_Inner Classes - Fatal编程技术网

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
有问题。我想知道如何在class
KeyboardEvents
中将
SnakeGame
制作成全局类型。现在,像
DirectionKeyboard
这样的嵌套类不知道蛇游戏的类型是什么,因为它只看到see
KeyboardEvents
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);
    }
};