无法将超类强制转换为子类

时间:2021-07-20 02:56:51

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:

抽象的init方法:

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:

如何将我的抽象接口转换为具体实现?我想添加一个newInitiationSettings-Method,它将返回一个IInitiationSettings对象,我将它传递给init方法,以便有一个干净的代码。 (我希望我的游戏代码看起来像这样:

GraphicsFactory::init(GraphicsFactory::newInitiationSettings(args));

)

Any ideas?

2 个解决方案

#1


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.

这里的根本错误是尝试将对象本身转换为抽象init方法中的其他类型。向上(即向基类)转换会导致对象切片,因为它只复制基类的数据。这通常很糟糕,但向下投射可能是不可能的。所以编译器不会让你。

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:

你真正想做的是在引用或指针级别工作。松散地说,引用是指针的语法糖,指向对象的指针可以替代指向其基类之一的指针。这就是为什么你可以通过类型为base&的参数传递派生的原因。但是当你试图得到你的派生时,你必须要求派生的或派生的*。在您的情况下,这看起来更像是其中之一:

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.

如果您确定initSettings将引用OxygineInitiationSettings实例,您可以而且应该使用static_cast而不是dynamic_cast。如果您不确定,您应该确定或使用dynamic_cast而不是static_cast。请注意,动态引用强制转换将引发std :: bad_cast异常,如果initSettings引用的实际对象实际上不是OxygineInitiationSettings,则动态指针强制转换将返回空指针。

#2


Dynamic_cast can be performed from virtual class, that is class which have virtual methods. Simply adding dummy() method like that:

Dynamic_cast可以从虚拟类执行,即具有虚方法的类。只需添加像这样的dummy()方法:

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.

会解决问题。

#1


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.

这里的根本错误是尝试将对象本身转换为抽象init方法中的其他类型。向上(即向基类)转换会导致对象切片,因为它只复制基类的数据。这通常很糟糕,但向下投射可能是不可能的。所以编译器不会让你。

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:

你真正想做的是在引用或指针级别工作。松散地说,引用是指针的语法糖,指向对象的指针可以替代指向其基类之一的指针。这就是为什么你可以通过类型为base&的参数传递派生的原因。但是当你试图得到你的派生时,你必须要求派生的或派生的*。在您的情况下,这看起来更像是其中之一:

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.

如果您确定initSettings将引用OxygineInitiationSettings实例,您可以而且应该使用static_cast而不是dynamic_cast。如果您不确定,您应该确定或使用dynamic_cast而不是static_cast。请注意,动态引用强制转换将引发std :: bad_cast异常,如果initSettings引用的实际对象实际上不是OxygineInitiationSettings,则动态指针强制转换将返回空指针。

#2


Dynamic_cast can be performed from virtual class, that is class which have virtual methods. Simply adding dummy() method like that:

Dynamic_cast可以从虚拟类执行,即具有虚方法的类。只需添加像这样的dummy()方法:

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.

会解决问题。