通过将对象显式存储为基类来抑制虚拟机制? [复制]

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 代替抽象基类。 好吧,currentSceneGameScene,而不是 TutorialLevel 或任何其他派生类。你观察object slicing @Ted:我确实尝试过,但没有效果,但现在我明白了原因(谢谢!) @Igor:是的,这很令人沮丧,因为我已经遇到过。 (我会学习的,谢谢你的解释) 【参考方案1】:

currentScene GameScene。你已经这样声明了。它永远不会是GameSceneGameScene 不是 TestLevelTutorialLevel;这是一个GameScene。当您将TestLevelTutorialLevel 对象分配给currentScene 时,您就是slicing。

C++ 中的多态性仅适用于指针和引用。指向GameScene 的指针或引用可以引用TestLevelTutorialLevel 对象,但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:那个我知道,是的,我会的,谢谢。

以上是关于通过将对象显式存储为基类来抑制虚拟机制? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

<继承问题>可以把基类对象赋值给子类对象么?

C#通过反射将派生类转换为基类异常

无法将参数 1 从派生指针转换为基类指针引用

C++ 容器与继承

向上强制转换和向下强制转换

如何将定义为基类的变量保存为 json?