通过将对象显式存储为基类来抑制虚拟机制? [复制]
Posted
技术标签:
【中文标题】通过将对象显式存储为基类来抑制虚拟机制? [复制]【英文标题】:Suppressed the virtual mechanism by storing object explicitly as base class? [duplicate] 【发布时间】:2020-05-17 03:11:58 【问题描述】:如你所料,我遇到了一个我无法回答且只能猜测的问题。
运行时多态是目标,使用虚拟机制,但我得到的结果就像我在抑制它的同时调用了该方法;就像我调用基类方法一样。
我只能猜测我正在以某种方式这样做,调用来自一个是基类的对象,尽管它是作为派生类构造的。因此,构造为派生,存储为基。
我确实将它作为静态基类变量存储在 cpp 中,并与多个外部函数接口以在其他地方访问。 (也许,这就是问题所在?)
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 );
所以,我遵循了一种模式,该模式与 SceneInit() 一起调用 LevelInit(),它在派生类中被覆盖。如果我在 NewScene() 中使用任一派生类构造函数,我会在运行时获得那些 LevelInit() 结果。我认为将此模式与 UpdateScene() 一起使用是安全的。
我看到的是 UpdateScene() 称为 GameScene::UpdateLevel(),尽管它在子类中被明显覆盖,就像 LevelInit() 一样。
我的(疯狂的)猜测是,我正在调用 UpdateLevel(),就好像我已经明确地将其转换为 GameScene。 :\
也许,这是因为我将 currentScene 存储为 GameScene? (但是,这不是违背了多态性的目的吗?)
我遗漏了一些关于存储 currentScene 或调用 UpdateLevel() 的内容。我试过这样打电话:
GameScene *s = currentScene;
s->UpdateLevel();
读完之后,作为一个指针,虚拟机制应该找到方法的最衍生版本。 (但是唉……)
我希望我能在这里或其他地方找到一个示例,但我的搜索指出了构造函数/解构函数中的虚拟问题,或者只是不使用“虚拟”关键字等。
【问题讨论】:
不相关:“gcc 抱怨 w/o
” - 尝试使用 = 0
代替抽象基类。
好吧,currentScene
是 GameScene
,而不是 TutorialLevel
或任何其他派生类。你观察object slicing
@Ted:我确实尝试过,但没有效果,但现在我明白了原因(谢谢!)
@Igor:是的,这很令人沮丧,因为我已经遇到过。 (我会学习的,谢谢你的解释)
【参考方案1】:
currentScene
是GameScene
。你已经这样声明了。它永远不会是GameScene
。 GameScene
不是 TestLevel
或 TutorialLevel
;这是一个GameScene
。当您将TestLevel
或TutorialLevel
对象分配给currentScene
时,您就是slicing。
C++ 中的多态性仅适用于指针和引用。指向GameScene
的指针或引用可以引用TestLevel
或TutorialLevel
对象,但GameScene
对象不能成为TestLevel
或@ 987654337@.
这归结为currentScene
需要是指向GameScene
而不是GameScene
的(智能)指针。然后它可以指向派生自GameScene
的任何类的动态分配对象。例如:
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>() );
// ...
【讨论】:
在销毁GameScene
后代时,基类中的析构函数也应设为虚拟,以免被切片。
谢谢你,迈尔斯。我之前确实遇到过物体切片,所以手掌朝向脸。感谢您的明确解释。 (当然)
@Ted:那个我知道,是的,我会的,谢谢。以上是关于通过将对象显式存储为基类来抑制虚拟机制? [复制]的主要内容,如果未能解决你的问题,请参考以下文章