通过将对象显式存储为基础 class 来抑制虚拟机制?
Suppressed the virtual mechanism by storing object explicitly as base class?
如您所料,我遇到了一个我无法回答且只能猜测的问题。
运行时多态性是目标,使用虚拟机制,但我得到的结果就像我在抑制它的同时调用了方法;就像我调用基本 class 方法一样。
我只能猜测我正在以某种方式这样做,调用来自一个对象,该对象 是 一个基础 class,尽管它是作为派生对象构造的class。所以,构建为派生,存储为基础。
我确实将其存储为 cpp 中的静态基础 class 变量,并与多个外部函数接口以访问其他地方。 (也许,这就是陷阱?)
GameScene.h:
class GameScene {
public:
GameScene() { SceneInit(); }
~GameScene() { }
virtual void LevelInit() { } // gcc complains w/o {}
void SceneInit();
virtual void UpdateLevel( const float& timeDelta ) { } // gcc complains unless {} added
void UpdateScene( const float& timeDelta );
};
extern void NewScene( const GameScene& level );
extern void UpdateScene( const float& timeDelta );
class TestLevel : public GameScene {
public:
TestLevel() { SceneInit(); }
// implementation here in header
void LevelInit() override
{
// level-specific initialization that is apparent at runtime
}
void UpdateLevel( const float& timeDelta ) override
{
// level-specific checks and performance
// but, to test, I simply log "This is the test level"
}
};
class TutorialLevel : public GameScene {
public:
TutorialLevel() { SceneInit(); }
// implementation here in header
void LevelInit() override
{
// level-specific initialization that is apparent at runtime
}
void UpdateLevel( const float& timeDelta )
{
// level-specific checks and performance
// debug log "This is the tutorial level"
}
};
GameScene.cpp:
#include "GameScene.h"
static GameScene currentScene; // I am now wondering if this pattern is the problem (by explicitly storing this as the base class)
extern void NewScene( const GameScene& level )
{
currentScene = level;
}
extern void UpdateScene( const float& timeDelta )
{
currentScene.UpdateScene( timeDelta );
}
GameScene::SceneInit()
{
// general init
LevelInit(); // this _properly_ calls the subclass overridden version
// init completion
}
GameScene::UpdateScene( const float& timeDelta )
{
// general updating and game handling
UpdateLevel( timeDelta ); // this was _meant_ to call the overridden version, it does not
}
EntryPoint.cpp:
#include "GameScene.h"
int main()
{
//NewScene( TestLevel() );
NewScene( TutorialLevel() );
float deltaTime;
while (gameLoop)
{
deltaTime = SecondsSinceLastFrame(); // pseudo
UpdateScene( deltaTime );
}
}
因此,我遵循了一种与调用 LevelInit() 的 SceneInit() 一起工作的模式,该模式在派生的 classes 中被覆盖。如果我在 NewScene() 中使用派生的 class 构造函数,我会在运行时得到那些 LevelInit() 结果。我认为将此模式与 UpdateScene() 一起使用是安全的。
我看到的是 UpdateScene() 称为 GameScene::UpdateLevel(),尽管它在子classes 中明显被覆盖,就像 LevelInit() 一样。
我的(大胆的)猜测是,我 是 调用 UpdateLevel() 就好像我已经明确地将其转换为 GameScene 一样。 :\
也许,这是因为我将 currentScene 存储为 GameScene? (但是,这不是破坏了多态性的目的吗?)
我遗漏了有关存储 currentScene 或调用 UpdateLevel() 的信息。我试过这样打电话:
GameScene *s = currentScene;
s->UpdateLevel();
阅读后,作为指针,虚拟机制应该找到该方法的最派生版本。 (可惜……)
我希望我能在这里或其他地方找到一个示例,但我的搜索指出 constructors/deconstructors 中的虚拟存在问题,或者只是没有使用 'virtual' 关键字等
currentScene
是一个GameScene
。你已经这样声明了。它永远不会是 GameScene
。 GameScene
不是 TestLevel
或 TutorialLevel
;这是一个GameScene
。当您将 TestLevel
或 TutorialLevel
对象分配给 currentScene
时,您就是 slicing 它。
C++ 中的多态性仅适用于指针和引用。 GameScene
的指针或引用可以 引用 到 TestLevel
或 TutorialLevel
对象,但 GameScene
对象不能 成为一个TestLevel
或TutorialLevel
.
这归结为 currentScene
需要是指向 GameScene
而不是 GameScene
的(智能)指针。然后它可以指向从 GameScene
派生的任何 class 的动态分配对象。例如:
static std::unique_ptr<GameScene> currentScene;
extern void NewScene( std::unique_ptr<GameScene> level )
{
currentScene = std::move(level);
}
int main()
{
NewScene( std::make_unique<TutorialLevel>() );
// ...
}
如您所料,我遇到了一个我无法回答且只能猜测的问题。
运行时多态性是目标,使用虚拟机制,但我得到的结果就像我在抑制它的同时调用了方法;就像我调用基本 class 方法一样。
我只能猜测我正在以某种方式这样做,调用来自一个对象,该对象 是 一个基础 class,尽管它是作为派生对象构造的class。所以,构建为派生,存储为基础。
我确实将其存储为 cpp 中的静态基础 class 变量,并与多个外部函数接口以访问其他地方。 (也许,这就是陷阱?)
GameScene.h:
class GameScene {
public:
GameScene() { SceneInit(); }
~GameScene() { }
virtual void LevelInit() { } // gcc complains w/o {}
void SceneInit();
virtual void UpdateLevel( const float& timeDelta ) { } // gcc complains unless {} added
void UpdateScene( const float& timeDelta );
};
extern void NewScene( const GameScene& level );
extern void UpdateScene( const float& timeDelta );
class TestLevel : public GameScene {
public:
TestLevel() { SceneInit(); }
// implementation here in header
void LevelInit() override
{
// level-specific initialization that is apparent at runtime
}
void UpdateLevel( const float& timeDelta ) override
{
// level-specific checks and performance
// but, to test, I simply log "This is the test level"
}
};
class TutorialLevel : public GameScene {
public:
TutorialLevel() { SceneInit(); }
// implementation here in header
void LevelInit() override
{
// level-specific initialization that is apparent at runtime
}
void UpdateLevel( const float& timeDelta )
{
// level-specific checks and performance
// debug log "This is the tutorial level"
}
};
GameScene.cpp:
#include "GameScene.h"
static GameScene currentScene; // I am now wondering if this pattern is the problem (by explicitly storing this as the base class)
extern void NewScene( const GameScene& level )
{
currentScene = level;
}
extern void UpdateScene( const float& timeDelta )
{
currentScene.UpdateScene( timeDelta );
}
GameScene::SceneInit()
{
// general init
LevelInit(); // this _properly_ calls the subclass overridden version
// init completion
}
GameScene::UpdateScene( const float& timeDelta )
{
// general updating and game handling
UpdateLevel( timeDelta ); // this was _meant_ to call the overridden version, it does not
}
EntryPoint.cpp:
#include "GameScene.h"
int main()
{
//NewScene( TestLevel() );
NewScene( TutorialLevel() );
float deltaTime;
while (gameLoop)
{
deltaTime = SecondsSinceLastFrame(); // pseudo
UpdateScene( deltaTime );
}
}
因此,我遵循了一种与调用 LevelInit() 的 SceneInit() 一起工作的模式,该模式在派生的 classes 中被覆盖。如果我在 NewScene() 中使用派生的 class 构造函数,我会在运行时得到那些 LevelInit() 结果。我认为将此模式与 UpdateScene() 一起使用是安全的。
我看到的是 UpdateScene() 称为 GameScene::UpdateLevel(),尽管它在子classes 中明显被覆盖,就像 LevelInit() 一样。
我的(大胆的)猜测是,我 是 调用 UpdateLevel() 就好像我已经明确地将其转换为 GameScene 一样。 :\
也许,这是因为我将 currentScene 存储为 GameScene? (但是,这不是破坏了多态性的目的吗?)
我遗漏了有关存储 currentScene 或调用 UpdateLevel() 的信息。我试过这样打电话:
GameScene *s = currentScene;
s->UpdateLevel();
阅读后,作为指针,虚拟机制应该找到该方法的最派生版本。 (可惜……)
我希望我能在这里或其他地方找到一个示例,但我的搜索指出 constructors/deconstructors 中的虚拟存在问题,或者只是没有使用 'virtual' 关键字等
currentScene
是一个GameScene
。你已经这样声明了。它永远不会是 GameScene
。 GameScene
不是 TestLevel
或 TutorialLevel
;这是一个GameScene
。当您将 TestLevel
或 TutorialLevel
对象分配给 currentScene
时,您就是 slicing 它。
C++ 中的多态性仅适用于指针和引用。 GameScene
的指针或引用可以 引用 到 TestLevel
或 TutorialLevel
对象,但 GameScene
对象不能 成为一个TestLevel
或TutorialLevel
.
这归结为 currentScene
需要是指向 GameScene
而不是 GameScene
的(智能)指针。然后它可以指向从 GameScene
派生的任何 class 的动态分配对象。例如:
static std::unique_ptr<GameScene> currentScene;
extern void NewScene( std::unique_ptr<GameScene> level )
{
currentScene = std::move(level);
}
int main()
{
NewScene( std::make_unique<TutorialLevel>() );
// ...
}