Exposing Multi-Level Inheritance with virtual functions

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Exposing Multi-Level Inheritance with virtual functions

Jay Riley
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
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig