保持抽象类型的引用/指针

C++ Keeping a reference /pointer of an abstract type

本文关键字:引用 指针 类型 抽象 抽象类      更新时间:2023-10-16

我是c++的新手,这个问题可能看起来很无聊,因为我只是一个Java/Actionscript3,我从来没有处理过内存相关的事情。

总之,关于我的问题:场景是一个抽象类(所以我可以从它派生,并有多个场景,如MainScene等)

我想让SceneManager做的是有一个指向所选场景(curSc)的指针/引用。然后像这样设置场景:setScene(&someScene)

但是据我所知,要有一个指针,我还必须像这样初始化它:curSc =新场景;但是它不允许我这样做,因为Scene是一个抽象类。

class Scene {
public:
    Scene(void){}
    virtual ~Scene(void){}
    virtual void update() = 0;
    virtual void render() = 0;
};

class SceneManager {
public:
    SceneManager(void);
    ~SceneManager(void);
    void setScene(Scene *sc);
    Scene* curSc;
}

到目前为止,在我看来,在这种情况下使用指针是错误的,它不会工作。但是我很想知道如何实现我在这里试图获得的功能

Thank you very much

编辑请求:我就是这么用的:

首先,我有一个名为GameScene的派生类,它是:

class GameScene : public Scene 
{
public:
    GameScene(void);
    void render();
    void update();
}

在我的main()函数我有:

GameScene gamescene;
ScreenManager manager;
manager.setScene(&gamescene);

你需要一个具体的Scene派生类:

class MyScene: public Scene {
public:
   MyScene(void){}
   virtual ~MyScene(void){}
   virtual void update();
   virtual void render();
};

和void setScene(Scene *sc)将是:

void setScene(Scene *sc)
{
  curSc = (Scene*)sc;
}

sc在本例中将是MyScene指针。抽象类实例(即接口)不能被创建,Scene在这里只是一个接口。

没错。你不能做

curSc = new Scene  

因为它是抽象的。如果你真的想声明一个Scene的实例,那么让它非抽象。即实现所有的方法。

(我认为这是你打算做的)创建一个继承自Scene并实现所有虚拟方法的类。

class View : public Scene {
public:
   View(){}
   virtual ~View(void){}
   virtual void update();
   virtual void render();
};

并实现像

这样的虚方法
void View::update() {
//
}
void View::render() {
//
}

然后你可以实现setScene作为

void SceneManager::setScene(Scene *sc)
{
  curSc = sc;
}

并将其命名为

SceneManager smag;
Scene *nsc = new View;
smag.setScene(nsc);

在这里使用指针并没有错。但与引用不同的是,指针敦促它的用户考虑NULL。这是警告。参考也可以参考NULL,但增加防御会把你引向"黑暗面"。因此,可以合理地假设引用将指向活动对象,从这个意义上说,引用比指针更好。

现在,如果你真的真的想保留引用,你可以使用就地构造技术,因为你可以(重新)通过构造函数赋值引用:

class SceneManager {
public:
    SceneManager(Scene& sc) : curSc(sc) {}
    ~SceneManager(void);
    SceneManager& setScene(Scene &sc) {
        SceneManager* cheatCompiler = new(this) SceneManager(sc);
        return *cheatCompiler;
    }
    Scene& curSc; 
}

注意,这是一种奇怪的东西。因为编译器总是试图比我们聪明,所以我不能保证它在所有情况下都有效。

尽管如此,我还是建议你使用指针。如果你不想一直检查NULL,你可以实现NULL对象模式。

应该使用智能指针,并且不要将成员变量设为public。例子:

class Scene {
public:
    virtual ~Scene(){}
    virtual void update() = 0;
    virtual void render() = 0;
};
class MyScene : public Scene {
public:
    virtual void update () { /*...*/ }
    virtual void render () { /*...*/ }
};
class SceneManager {
public:
    SceneManager();
    ~SceneManager();
    void setScene(const std::shared_ptr<Scene> & sc) {
       curSc = sc;
    }
private:
    std::shared_ptr<Scene> curSc;
};
void someProc () {
    std::shared_ptr<Scene> sc = std::make_shared<MyScene> ();  
    auto manager = std::make_shared<SceneManager> ();
    manager->setScene (sc);
    // ...
}

如果没有智能指针,这看起来就像(但是如果不再需要new创建的对象,请记住delete):

class Scene {
public:
    virtual ~Scene(){}
    virtual void update() = 0;
    virtual void render() = 0;
};
class MyScene : public Scene {
public:
    virtual void update () { /*...*/ }
    virtual void render () { /*...*/ }
};
class SceneManager {
public:
    SceneManager();
    ~SceneManager();
    void setScene(Scene * sc) {
       curSc = sc;
    }
private:
    Scene * curSc;
};
void someProc () {
    Scene * sc = new MyScene;
    SceneManager * manager = new SceneManager;
    manager->setScene (sc);
    // ...
}