I'm currently writing an abstraction layer between my game and the rendering engine. Unfortunately, I came accross a problem: I just can't seem to cast a superclass (The abstract interface) to a subclass (The implementation for a concrete engine). Here is my code:
IInitationSettings.h
class IInitationSettings {};
OxygineInitiationSettings.h
#include "IInitiationSettings.h"
#include "core/oxygine.h"
class OxygineInitiationSettings : public IInitationSettings, public oxygine::core::init_desc {
public:
OxygineInitiationSettings(const char* title, bool vsync, bool fullscreen, int width, int height);
};
OxygineInitiationSettings.cpp
#include "OxygineInitiationSettings.h"
OxygineInitiationSettings::OxygineInitiationSettings(const char* title, bool vsync, bool fullscreen, int width, int height) : oxygine::core::init_desc() {
this->title = title;
this->vsync = vsync;
this->fullscreen = fullscreen;
this->w = width;
this->h = height;
}
The abstract init method:
static void init(IInitiationSettings& initSettings);
void GraphicsFactory::init(IInitiationSettings& initSettings){
#ifdef USE_OXYGINE_RENDERING
OxygineInitiationSettings settings = initSettings; //Does not work
oxygine::core::init_desc desc = initSettings; // Does not work
oxygine::core::init((oxygine::core::init_desc)((OxygineInitiationSettings)initSettings)); //Does not work
#endif
}
How do I cast my abstract interface to the concrete implementation? I want to add a newInitiationSettings-Method too, which will return an IInitiationSettings Object which I will pass into the init method, in order to have a clean code. (I want my ingame-code look like this:
GraphicsFactory::init(GraphicsFactory::newInitiationSettings(args));
)
Any ideas?
The fundamental mistake here is an attempt to cast the object itself to a different type in your abstract init method. Casting upward (i.e. towards the base class) results in object slicing, as it makes a copy of just the base class's data. That's typically bad, but casting downward is potentially impossible. So the compiler won't let you.
What you really want to do is work at the reference or pointer level. Speaking loosely, a reference is syntactic sugar for a pointer, and a pointer to an object is substitutable for a pointer to one of its base classes. That's why you could pass a derived
through a parameter of type base&
. But when you try to get your derived
back, you have to ask for a derived&
or a derived*
. In your case this looks more like one of these:
static_cast<OxygineInitiationSettings&>(initSettings) // or
dynamic_cast<OxygineInitiationSettings&>(initSettings)
or, if you need a pointer, perhaps this:
static_cast<OxygineInitiationSettings*>(&initSettings) // or
dynamic_cast<OxygineInitiationSettings*>(&initSettings)
If you know for certain that initSettings
will refer to an OxygineInitiationSettings
instance, you can and should use static_cast
instead of dynamic_cast
. If you aren't certain, you should either become certain or use dynamic_cast
instead of static_cast
. Note that the dynamic reference cast will raise a std::bad_cast
exception, and the dynamic pointer cast will return a null pointer if the actual object referenced by initSettings
isn't actually an OxygineInitiationSettings
.
Dynamic_cast can be performed from virtual class, that is class which have virtual methods. Simply adding dummy() method like that:
class IInitationSettings {
virtual void dummy() {}
};
and changing from implicit to dynamic cast:
void GraphicsFactory::init(IInitationSettings& initSettings) {
OxygineInitiationSettings settings =
dynamic_cast<OxygineInitiationSettings&>(initSettings); //Does indeed work
}
would resolve problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With