When looking at
sfWindow and
sfRenderWindow, they are defined like this:
struct sfWindow
{
sf::Window This;
};
struct sfRenderWindow
{
sf::RenderWindow This;
sfView DefaultView;
sfView CurrentView;
};
This is already the first problem -- we store a concrete
sf::Window value, which is not polymorphic. Instead, we should store
sf::Window*, which can point to a
sf::RenderWindow behind the scenes (more about memory management later).
Once we have that, an upcast could be implemented:
sfWindow* sfRenderWindow_upcast(sfRenderWindow* renderWindow)
{
sfWindow window; // assuming C++03 no init-list
window.This = &renderWindow->This; // 'This' has type sf::Window*
return window;
}
Memory managementMemory management and ownership makes this a bit trickier. Normally, every
sfWindow is created using its create and destroyed using its destroy function. Manual, but very straightforward semantics.
Now, it would be possible that a
sfWindow actually points to a
sfRenderWindow -- so who should destroy it? One could attempt some
std::shared_ptr tricks, however that doesn't work well with C -- copying a struct is always a bytewise copy, so ref-counts would need to be managed manually. There is no win with smart pointers here.
We have two options: either we allow polymorphic destruction in
sfWindow_destroy or we don't.
If we don't, we should probably have a runtime check like:
extern "C" void sfWindow_destroy(sf::Window *window) {
assert(dynamic_cast<sf::RenderWindow*>(window.This) == nullptr);
delete window.This;
delete window;
}
(Not sure if this works dependency-wise; since
RenderWindow is in Graphics. Of course, there could in the future also be other derived classes. Maybe
typeid would be safer, or a bool flag
sfWindow::isUpcast).