I've been looking around and I can find tons of information about how to wrap
shallow inheritance hierarchys with virtual/pure virtual functions, but none of
them show how to do multi level inheritance. I'm unsure if I'm supposed to
inherit from the wrapper or the base class for the virtual functions.
Essentially, I'm asking what the best way to wrap this, the various methods
I've tried usually result in error messages about the wrapper not being
available
For Instance I have this hierarchy:
class DrawInterface { public: DrawInterface(int drawPriority
= 0, bool drawing = true) : DrawPriority(drawPriority), Drawing(drawing)
{
} bool IsDrawing() const {
return Drawing; } void SetDrawing(const bool
value) { Drawing = value; }
virtual void Draw(sf::RenderWindow &window) = 0;
virtual void Draw(sf::RenderWindow &window, sf::Shader &shader) = 0;
int GetDrawPriority() const { return
DrawPriority; } private: bool Drawing;
int DrawPriority; };
class AnimatedDraw : public DrawInterface { public:
AnimatedDraw(bool paused = false, int drawPriority = 0) :
DrawInterface(drawPriority), Paused(paused) { }
virtual void Update(const sf::Uint32 time, const float
TimeScale = 1.0) = 0; virtual void Update(const float time, const
float TimeScale = 1.0) = 0; virtual void SetPause(const bool value)
{ Paused = value; } virtual
bool GetPause() const { return Paused;
} protected: bool Paused; private: };
class InputInterface { public: InputInterface(bool
acceptingInputs = true) : AcceptingInputs(acceptingInputs) {
} bool IsAcceptingInputs() const {
return AcceptingInputs; } void
SetAcceptingInputs(const bool value) {
AcceptingInputs = value; } virtual bool
HandleKeyPressed(const sf::Uint32 time, const ::Input::InputModule*
inputModule, ::Input::PlayerInput pInput, ::Input::InputAction& action) {
return false;} virtual bool HandleKeyReleased(const sf::Uint32
time, const ::Input::InputModule* inputModule, ::Input::PlayerInput pInput,
::Input::InputAction& action) { return false;} private:
bool AcceptingInputs; };
class Screen : public ::Input::InputInterface, public AnimatedDraw
{ public: Screen(const std::string& name,
::Engine* engine, int id); int GetID() const;
const std::string& GetScreenName() const; void
SetScreenName(const std::string& name);
bool AddOwner(const std::string& name, ScreenStack*
stack); bool RemoveOwner(const std::string& name);
bool HasOwner(const std::string& name) const;
const boost::unordered_map<std::string, ScreenStack*>& GetOwners() const;
bool operator==(const Screen& screen) const;
bool operator!=(const Screen& screen) const; private:
Engine* engine; int ScreenID;
std::string ScreenName; sf::Uint32 LastUpdate;
boost::unordered_map<std::string, ScreenStack*> OwningStacks;
friend class ScreenManager; };
I want to be able to create various types of screens in Python so obviously I
need to expose/wrap all the base classes, but this is where I get a little
unclear about if I should be inheriting from the wrappers or the base classes,
and how I should be representing these clases in python. My initial attempt at
wrapping looked something like this:
class DrawInterfaceWrap : public DrawInterface { public:
DrawInterfaceWrap(PyObject* self, int priority = 0, bool drawing = true) :
self(self), DrawInterface(priority, drawing) {
} DrawInterfaceWrap(PyObject* self, const
DrawInterface& src) : self(self), DrawInterface(src) {
} void Draw(sf::RenderWindow &window) override
{ call_method<void>(self, "Draw",
boost::ref(window)); } void Draw(sf::RenderWindow
&window, sf::Shader& shader) override {
call_method<void>(self, "Draw", boost::ref(window), boost::ref(shader));
} private: PyObject* self; };
class AnimatedDrawWrap : public AnimatedDraw { public:
AnimatedDrawWrap(PyObject* self, int priority = 0, bool paused = true) :
self(self), AnimatedDraw(paused, priority) {
} //??? not sure how to do ta proper copy
construction on self AnimatedDrawWrap(PyObject* self, const
AnimatedDraw& src) : self(self), AnimatedDraw(src) {
} void Update(const sf::Uint32 time, const float
TimeScale = 1.0) override {
call_method<void>(self, "Update", time, TimeScale); }
void Update(float time, const float TimeScale = 1.0) override {
call_method<void>(self, "Update", time, TimeScale);
} private: PyObject* self; };
class_<DrawInterfaceWrap>("DrawInterface", init<boost::python::optional<int,
bool> >()) .def(init<const DrawInterface&>())
.def("Draw", pure_virtual((void
(DrawInterface::*)(sf::RenderWindow&))&DrawInterface::Draw))
.def("Draw", pure_virtual((void (DrawInterface::*)(sf::RenderWindow&,
sf::Shader&))&DrawInterface::Draw)) .def("IsDrawing",
&DrawInterface::IsDrawing) .def("SetDrawing",
&DrawInterface::SetDrawing) .def("GetDrawPriority",
&DrawInterface::GetDrawPriority) ;
class_<AnimatedDrawWrap, bases<DrawInterfaceWrap> >("AnimatedDraw",
init<boost::python::optional<int, bool> >())
.def(init<const AnimatedDraw&>()) .def(init<const
AnimatedDrawWrap&>()) .def("Update", pure_virtual((void
(AnimatedDraw::*)(const sf::Uint32, const float))&AnimatedDraw::Update))
.def("Update", pure_virtual((void (AnimatedDraw::*)(const float,
const float))&AnimatedDraw::Update)) .def("GetPause",
&AnimatedDraw::GetPause) .def("SetPause",
&AnimatedDraw::SetPause) ;
class InputInterfaceWrap : public ::Input::InputInterface { public:
InputInterfaceWrap(PyObject* self, bool acceptingInputs = true) :
self(self), ::Input::InputInterface(acceptingInputs) { }
virtual bool HandleKeyPressed(const sf::Uint32 time, const
::Input::InputModule* inputModule, ::Input::PlayerInput pInput,
::Input::InputAction& action) override {
return call_method<bool>(self, "HandleKeyPressed", time, ptr(inputModule),
pInput, boost::ref(action)); } virtual bool
HandleKeyReleased(const sf::Uint32 time, const ::Input::InputModule*
inputModule, ::Input::PlayerInput pInput, ::Input::InputAction& action)
override { return call_method<bool>(self,
"HandleKeyReleased", time, ptr(inputModule), pInput, boost::ref(action));
} private: PyObject* self; };
class_<InputInterfaceWrap, boost::noncopyable>("InputInteface",
init<boost::python::optional<bool> >())
.def("HandleKeyPressed",
pure_virtual(&::Input::InputInterface::HandleKeyPressed))
.def("HandleKeyReleased",
pure_virtual(&::Input::InputInterface::HandleKeyReleased))
.def("IsAcceptingInputs", &::Input::InputInterface::IsAcceptingInputs)
.def("SetAcceptingInputs",
&::Input::InputInterface::SetAcceptingInputs) ;
class_<Screen, bases<Graphics::AnimatedDraw, ::Input::InputInterface>
>("Screen", init<const std::string&, ::Engine*, int>())
.def("GetID", &Screen::GetID) .def("GetScreenName",
&Screen::GetScreenName, return_value_policy<reference_existing_object>())
.def("HasOwner", &Screen::HasOwner)
.def("RemoveOwner", &Screen::RemoveOwner)
.def("SetScreenName", &Screen::SetScreenName) ;
I cant export this wrapping because boost python won't let me have initializers
for abstract classes. I attempted to fix this by changing all the pure virtual
functions to virtual functions, and adding a Default method for each virtual
function in the wrapper. I was able to compile like this, but python hits a
runtime error saying a wrapper is unavailable for base class AnimatedDraw, so
obviously my exports are sstill incorrect. I'm looking for advice on how to
export this hierarchy. Can I keep these functions pure virtual and have
initializers or will I need to add a default implementation? Further to that,
should I be inheriting from the wrappers and not the base classes? I really
just want this to work where I can inherit from Screen and implement Update,
Draw and HandleKeys for each screen.
I had an additional question. How do you correctly implement a copy
constructors on the wrapper classes?for instance
this:AnimatedDrawWrap(PyObject* self, const AnimatedDraw& src) : self(self),
AnimatedDraw(src) {
}
I assume is incorrect since I'm not making a proper copy of the self pointer.
What's the correct way to do this?
My last question is more a sylistic one. I've seen multiple ways to implement
the virtual function override. I've chosen the call_method form:
void Update(const sf::Uint32 time, const float TimeScale = 1.0) override
{ call_method<void>(self, "Update", time,
TimeScale); }
just because that's what I'm used to. Is there a "better" or more correct way
to do this? or is it a purely stylistic choice?
Sorry for the cluster of code, I hope my questions are clear. I can clean out
some parts of the code that I don't think are relevant, but since the classes
are fairly small to begin with, I figured it'd be okay.
Thanks on advance for any help :) _______________________________________________
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig