6

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?

4
  • 2
    Not sure what you're asking. How to do static_cast or dynamic cast? How to avoid the need to cast?
    – Ami Tavory
    Commented May 10, 2015 at 10:18
  • What exactly doesn't work? Could you provide some error messages? Commented May 10, 2015 at 10:22
  • @AmiTavory Nah, I'm asking why I can't cast my superclass IInitationSettings to my subclass OxygineInitationSettings
    – Fly
    Commented May 10, 2015 at 10:42
  • @MateuszKacprzak Well, just IntelliJ telling me that the casts I'm doing are impossible.
    – Fly
    Commented May 10, 2015 at 10:46

2 Answers 2

12

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.

2
  • Thanks for the answer; But unfortunately, it does not work. IntelliJ underlines static_cast and says "Invalid typeconversion"
    – Fly
    Commented May 10, 2015 at 14:45
  • Nevermind, it works, I mistyped "Initiation" in the header class =)
    – Fly
    Commented May 10, 2015 at 15:09
2

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.

2
  • 1
    Thanks, it works! But why do I need to add a dummy method to tell the compiler that the class is abstract? Meh, I liked Java interfaces & abstract-classes more...
    – Fly
    Commented May 10, 2015 at 14:48
  • 4
    It is semantically incorrect to not have a virtual destructor on the base class if you delete (manually or using any smart pointer wrapper) when type is a base class. So, no you don't need a dummy method. Use a virtual destructor instead; it's probably what you really want.
    – Nate
    Commented Jul 3, 2017 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.