【问题标题】:C++ - Polymorphic pointer to member functionsC++ - 指向成员函数的多态指针
【发布时间】:2013-06-06 14:29:01
【问题描述】:

我不太擅长 C++(但我熟悉 OOP/Java),但我必须为我的 C++ 类创建一个游戏。我想设置一种游戏引擎,类似于用 ActionScript 编写的 Flash 游戏。

我编写了这两个类,其中Actor 是一个基类(可能是抽象的),Player 应该实际实现它。

问题是我想避免函数addEventListenerhandle中的重复代码并重新声明_handlerMap,因为我想实现数据隐藏等。

我猜,问题在于_eventMap 应该包含handler 可以更改类Actor::*handlerPlayer::*handler 的值。有可能吗?

    class Actor {
    protected:
        typedef void(Actor::*handler)(Event);
        map<int, handler> _handlerMap;
    public:
        virtual void addEventListener(int ID, handler h) {
            _handlerMap.insert(std::make_pair(ID, h));
        };
        virtual void handle(int ID) {
            handler h = _handlerMap[ID];
            Event e;
            if (h)
                (this->*h)(e);
        }
        virtual void onUpdate(Event e) {
            cout << "Actor::onUpdate()" << endl;
        };
    };

class Player : public Actor {
    typedef void(Player::*handler)(Event);
    map<int, handler> _handlerMap;
public:
    void addEventListener(int ID, handler h) {
        _handlerMap.insert(std::make_pair(ID, h));
    };
    void handle(int ID) {
        handler h = _handlerMap[ID];
        Event e;
        if (h)
            (this->*h)(e);
    }
    void onKeydown(Event e) {
        cout << "Player::onKeyDown()" << endl;
    };
};

我希望可以将 Player 声明为:

class Player : public Actor {
        typedef void(Player::*handler)(Event);
 public:
        void onWhateverEvent(Event e);
 }

希望你能理解。

【问题讨论】:

  • 是否允许Actor 的其他实例注册处理程序? (即addEventListener 必须是公共成员吗?)
  • “问题,我猜,是_eventMap” -> 你是说_handlerMap吗?
  • 我能想到的最简单的解决方案是使用 std::functionstd::bind,在 C++11 中可用。

标签: c++ function pointers


【解决方案1】:

你需要这样的东西(未经测试):

class Dispatcher {
  public:
    virtual void dispatchEvent(Event*) = 0;
};

template <class C>
class DispatcherImpl : public Dispatcher
{
    typedef void(C::*handler)(Event* e);
    std::map<int, handler> _handlerMap;
    C* _owner;
  public:
    DispatcherImpl (C* c) : _owner(c) {}
    addEventListener(int ID, handler h) {
        _handlerMap.insert(std::make_pair(ID, h));
    }        
    void dispatchEvent(Event*)
    {
      handler h = handlerMap[e->id];
      if (h) (_owner->*h)(e);
    }
}

现在让每个类型的演员T 拥有一个DispatcherImpl&lt;T&gt;,一切就绪。您可能还有例如Player 继承自 DispatcherImpl&lt;Player&gt;

【讨论】:

  • dispatchEvent 必须返回一些东西才能例如让Player 将事件传递给Actor,以防Player 中没有针对此事件的特殊处理程序。此外,我宁愿使用map::find 而不是map::operator[] 来检查地图中是否存在元素。
  • @DyP:绝对不是。 Player Actor。你想传递给其他什么Actor?至于map::find,当然用。这个 sn-p 是严格的伪代码,不能按字面意思使用。
  • 你的意思是只有派生类型应该从DispatcherImpl继承?我还以为你的意思是 Actor 应该来自它;在这种情况下,您必须返回例如来自dispatchEventbool 指示是否已在当前_handlerMap 中找到事件ID,或者是否应将其传递给基类的调度程序进行处理。
  • @DyP:Player dispatcher 拥有 Actor 的所有功能。无需链接。
  • 我试过这个,但我不能让它工作。新的“Player”类现在有一个“DispatcherImpl”成员,我在 Player 的构造函数中将其初始化为 _dispatcher = new DispatcherImpl(this)。当我编写 player.getDispatcher()->dispatchEvent(eventID, event) 时,我收到此错误(在 Visual Studio 中):无法从 'std::basic_string<_elem>' 转换为 'void (__thiscall播放器::* )(int)'
【解决方案2】:

你怎么看这个? (Dispatcher和上面的DispatcherImpl一样)

template <class T>
class Entity {
    T *_instance;
    Dispatcher<T> *_dispatcher;
public:
    Entity() {
        _instance = new T();
        _dispatcher = new Dispatcher<T>(_instance);
    }
};
class Actor {
    //attirbutes and methods
};
class Player : public Actor {
    //attirbutes and methods
};

仅使用它:

Entity<Actor> *actor = new Entity<Actor>();
Entity<Player> *player = new Entity<Player>();
actor->getDispatcher()->addEventListener(0, &Actor::foo);
player->getDispatcher()->addEventListener(1, &Player::bar);
player->getDispatcher()->addEventListener(0, &Actor::foo); //inheritance

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-02
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多