Custom RTTI for use in script-defined types

2019-04-15 07:27发布

问题:

I'm developing a game engine in C++ that allows Python scripting. Here's an example of how functions can be defined in Python that are then called by the an event manager whenever a certain event occurs:

# Import some classes defined in C++
from cpp.event import PlayerDiesEvent, EventManager

def onPlayerDeath(event):
    pass

em = EventManager()
em.connect(PlayerDiesEvent, onPlayerDeath)
em.post(PlayerDiesEvent(...)) # Will call `onPlayerDeath`

The user can also define new types of events:

from cpp.event import Event, EventManager

class CustomEvent(Event):
    pass

def onCustomEvent(event):
    pass

em = EventManager()
em.connect(CustomEvent, onCustomEvent)
em.post(CustomEvent())

However, I would also like the messaging system to work with inheritance, which it currently does not. Here's what I mean:

from cpp.event import PlayerDiesEvent, EventManager

class CustomEvent(PlayerDiesEvent):
    pass

def onPlayerDeath(event):
    pass

def onCustomEvent(event):
    pass

em = EventManager()

em.connect(PlayerDiesEvent, onPlayerDeath)
em.connect(CustomEvent, onCustomEvent)

# This notifies both functions, because `CustomEvent` is a `PlayerDiesEvent`
em.post(CustomEvent(...))

# This notifies only `onPlayerDeath`
em.post(PlayerDiesEvent(...))

tld;dr: Is there any C++ library that would allow me to more easily create a custom RTTI system that works with inheritance? If not, any ideas how I might implement this more easily and perhaps more generally (preferably in a way that is agnostic to my actual use case)?

回答1:

I'm not familiar with boost::python; it might have some feature that makes this easier. I just know of a custom RTTI system that works pretty well:

Qt has a meta-object system, where reflection and a degree of dynamic behavior is added by having a metaobject associated with each class that knows about that class's ancestors and methods. It's kind of like Python's class objects. A virtual method is used to get the metaobject from instances. A custom compiler is used to generate these.

Qt's Python bindings then also create these metaobjects for Python classes, making them look almost identical to native QObjects classes as far as the meta-object system is concerned.


You need quite a bit less than Qt's general solution (you don't need info about methods/properties). So instead of a custom compiler, you could go with a C++-class definition macro that stores information about the class's ancestors. And then also update the information from the __metaclass__ when a Python subclass is created, and query it when you're dispatching a message.