【问题标题】:Superclass member pointer becomes null when accessed by subclass子类访问时超类成员指针变为空
【发布时间】:2021-03-25 10:22:40
【问题描述】:

我最近做了很多阅读,并决定尝试实现一个简单的状态模式来尝试看看事情是如何组合在一起的。

但是,我遇到了一个以前从未遇到过的问题:场景的子类 (Start) 似乎没有继承由超类的构造函数设置的指针的值。

这是代码

//main.cpp
#include "Game/game.hpp"
#include "Game/Scene/start.hpp"

int main()
{
    Game::Game *g = new Game::Game;
    Game::Scene::Start *s = new Game::Scene::Start(g);
    g->set_scene(s);
    g->loop();
    
    delete g;
    
    return 0;
}
//Game/Scene/Scene.hpp
#ifndef GAME_SCENE_H
#define GAME_SCENE_H

namespace Game
{
    class Game;
    namespace Scene
    {
        class Scene
        {
        public:
            Scene(Game *game);
            virtual ~Scene();

            virtual void handle_input() = 0;
            virtual void update();
        protected:
            Game *game;
        };
    }
}

#endif
//Game/Scene/Scene.cpp
#include "scene.hpp"

#include <iostream>

Game::Scene::Scene::Scene(Game *game): game(game) 
{
    std::cout << "Game::Scene::Scene::Scene() > game: " << this->game << std::endl;
}

Game::Scene::Scene::~Scene() {}

void Game::Scene::Scene::update()
{
    std::cout << "Game::Scene::Scene::update(): game: " << game << std::endl;
}
//Game/Scene/start.hpp
#ifndef GAME_SCENE_START_H
#define GAME_SCENE_START_H

#include "scene.hpp"

namespace Game
{
    namespace Scene
    {
        class Start:
            public Scene
        {
        public:
            Start(Game *game);
            
            void handle_input() override;
            void update() override;
        protected:
            Game *game;
        };
    }
}

#endif
//Game/Scene/start.cpp
#include "start.hpp"
#include "../game.hpp"

#include <iostream>

Game::Scene::Start::Start(Game *game): Scene(game) {
    std::cout << "Game::Scene::Start::Start() > game: " << this->game << std::endl;
}

void Game::Scene::Start::handle_input()
{}

void Game::Scene::Start::update()
{
    Scene::update();
    std::cout << "Game::Scene::Start::update(): game: " << game << std::endl;
    game->set_keep_going(false);
}
//Game/game.hpp
#ifndef GAME_H
#define GAME_H

#include "Scene/scene.hpp"
namespace Game
{
    class Game
    {
    public:
        Game();
        void loop();

        void set_keep_going(bool state);
        void set_scene(Scene::Scene *scene);
    private:
        bool keep_going;
        Scene::Scene *current_scene;
    };
}

#endif
//Game/game.cpp
#include "game.hpp"

#include <iostream>

Game::Game::Game(): 
    keep_going(true),
    current_scene(nullptr)
{}

void Game::Game::loop()
{
    while(keep_going && current_scene)
    {
        current_scene->handle_input();
        current_scene->update();
    }
    return;
}

void Game::Game::set_keep_going(bool state)
{
    keep_going = state;
}

void Game::Game::set_scene(Scene::Scene *scene)
{
    if(scene)
    {
        if(current_scene)
        {
            delete current_scene;
        }
        current_scene = scene;
    }
}

这是它生成的输出:

Game::Scene::Scene::Scene() > game: 00000210FA38B330
Game::Scene::Start::Start() > game: 0000000000000000
Game::Scene::Scene::update(): game: 00000210FA38B330
Game::Scene::Start::update(): game: 0000000000000000
Segmentation fault

如果我删除了在子类构造函数中用于调试的“this->”部分,则输出变为this

Game::Scene::Scene::Scene() > game: 000001D247B5B370
Game::Scene::Start::Start() > game: 000001D247B5B370
Game::Scene::Scene::update(): game: 000001D247B5B370
Game::Scene::Start::update(): game: 0000000000000000
Segmentation fault

这让我更奇怪的是它突然决定重置自己。

毫无疑问,我忽略了一件非常简单的事情,或者是我以前从未遇到过的一些指针恶作剧,但我对这里可能发生的事情感到困惑。

任何对我的代码的帮助或反馈都将得到应用。

【问题讨论】:

    标签: c++ pointers inheritance subclass


    【解决方案1】:

    您有两个成员变量Scene::gameStart::game。你永远不会设置Start::game。默认情况下,game 解析为Scene::game,并且基类的变量被隐藏。打开编译器警告,也许编译器会警告它,在这种特殊情况下不确定。

    修复:

    Game::Scene::Start::Start(Game *game): Scene(game), game(game)
     {
        std::cout << "Game::Scene::Start::Start() > game: " << this->game << std::endl;
    }
    

    或者只是删除Start::game 并使用来自Scene 的成员。这可能是您最初的意思,因此使用了 protected 限定符。

    如果您需要反馈 - 不要使用 new,而是使用 std::unique_ptr。更好的是,根本不使用 ptrs 这不是 Java。

    【讨论】:

    • 是的,就是这样。复制课程后一定忘记删除受保护的东西。我们的好奇心:“不要使用指针”是指原始指针吗?我们只是一般的指针?
    • @DangerDaisy 当前的 C++ 指南强烈建议使用智能指针作为所有权,而不是原始指针,它们(或引用)应该指示非拥有指针 - 一个从不负责释放的指针并且有办法检测内存是否还活着。后者可以基于程序的逻辑约束来完成。例如。你知道Game 总是比场景更长寿,所以他们可以有指向它的原始指针。当然你可以使用指针,抱歉措辞不是很清楚。
    • 没关系。根本不使用指针似乎有点奇怪。我知道我可能应该使用智能指针,但我总是在以一种或另一种方式使用它们时遇到问题,所以我倾向于使用老式的方式。最好对使用它们的正确程序进行一些测试。
    猜你喜欢
    • 2011-02-03
    • 2015-02-04
    • 2016-03-08
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    相关资源
    最近更新 更多