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.
会解决问题。