【问题标题】:How to make an object that can be referenced by everything? [duplicate]如何制作一个可以被所有东西引用的对象? [复制]
【发布时间】:2018-01-31 02:04:29
【问题描述】:

我正在尝试创建一个仅实例化一次的类 ShapeManager,并且有一个基类 Shape(及其所有子类)可以访问它。这将导致结构如下所示:

ShapeManager
Shape
Square
Triangle
Circle


#include "Shape.h" // so that i can use Shape in the vector

// This is instantiated once in main
class ShapeManager {
public:
    typedef std::vector<std::unique_ptr<Shape>> VecShape;
    typedef std::default_random_engine          DRE;

private:
    VecShape&   m_shapes;
    b2World&    m_world;
    DRE&        m_gen;

public:
    ShapeManager(VecShape& vectorShapes, b2World& world, DRE& gen) 
        : m_shapes(vectorShapes), m_world(world), m_gen(gen) {}

    VecShape& getShapeList() { return m_shapes; }
    b2World& getWorld() { return m_world; }
    DRE& getDRE() { return m_gen; }
};

#include "ShapeManager.h" // so that i can access it's member functions

class Shape {
protected:
    std::string m_name;

public:
    Shape() : m_name("Shape") {}
    std::string getName() { return m_name; }
};

我大大简化了我的代码以使其与我的问题相关。如果不清楚我在问什么,我会尝试进一步解释! 基本上我只想有一个类来管理我的形状对象并保存Shape's儿童将使用的数据,例如m_genm_world

编辑 1:我创建 ShapeManager 的主要动机是存储对 m_shapes、m_world 和 m_ge​​n 的引用,但我不希望每个形状对象都具有这 3 个引用变量。这意味着创建 Circle 必须在 ctor 中包含这 3 个参数,以及与圆相关的参数。

编辑 2:单例和/或依赖注入是两种设计模式,在实施时可以解决我的问题。 Here is some info on it.谢谢大家!

【问题讨论】:

  • 您可以存储ShapeManager(或类似的任何东西)的全局实例并使用它。
  • 警告:ShapeManager.h 包含 Shape.h,Shape.h 包含 ShapeManager.h。这是一个循环依赖。阅读Resolve build errors due to circular dependency amongst classes 可能会阻止未来的问题。
  • 为什么形状需要与形状管理器交互?我希望反过来。您可能将管理和服务混为一谈。
  • 我尝试在 main() 上方声明一个全局 ShapeManager,但 Shape 的子级仍然无法访问它。
  • 你在问如何制作一个 singleton 对象。这是一个众所周知的(虽然并不总是喜欢)模式,现在您知道要搜索什么词,使用它不会有任何问题。

标签: c++ inheritance


【解决方案1】:

您正在寻找的是单例设计模式。请看下面的代码:

class ShapeManager
{
public:
static ShapeManager& instance()
{
    static ShapeManager *instance = new ShapeManager();
    return *instance;
}

private:
    ShapeManager(){}

/*
    use this space to fill in your code
    */
}

您可以通过以下方式访问班级成员:

ShapeManager::instance().getDRE();

这仅限于类的单个实例。不需要实例化这个类的对象,事实上,你不能也可以从任何地方访问。

【讨论】:

  • 依赖注入比单例更好,除非你的对象非常轻量级以至于你负担不起额外的指针。当你发现你需要多个单例时,它允许模拟并为那一天做准备。
【解决方案2】:

不要试图让一个全局变量通过你的所有代码都可以访问。使某个对象只有需要它的人才能访问。因此,在 Shape 中创建一个私有 ShapeManager 并将其传递给 Shapes 构造函数。

Shape 必须有权访问ShapeManager 仍然很奇怪。

编辑 - 作者评论: 我创建 ShapeManager 的主要动机是存储对 m_shapes、m_world 和 m_ge​​n 的引用,但我不想每个形状对象都有这 3 个参考变量。

您可以拥有一个存储 3 个引用变量的结构,并且每个需要访问它们的对象都有一个私有结构。

其他一些文件:

struct myManagers {
ShapeManager *shapeMan;
WorldManager *worldMan;
GenManager *genMan;
}

形状.h:

#ifndef H_SHAPE // Include guards to avoid circular dependency
#define H_SHAPE
#include "ShapeManager.h" // so that i can access it's member functions

class Shape {
protected:
    std::string m_name;
    myManagers *myMan = nullptr;

public:
    Shape(myManagers *myManager) : m_name("Shape"), myMan(myManager) {}
    std::string getName() { return m_name; }
};

#endif

和用法会是这样的:

int main() {
myManagers GlobalManager;
GlobalManager.shapeMan = &ShapeManager;
// ... fill in other 2 managers

Shape myBall(&GlobalManager);
// this way myBall has access to all 3 references
}

ps:包含守卫几乎是唯一可以接受宏的场合

【讨论】:

  • 使用pragma once;
  • 我创建ShapeManager 的主要动机是存储对 m_shapes、m_world 和 m_ge​​n 的引用,但我不希望每个形状对象都有这 3 个引用变量。这意味着创建 Circle 必须在 ctor 中包含这 3 个参数,以及与圆圈相关的参数。
  • pragma once; 是非标准的,可能适用于任何现代编译器,但可能不会。 Pragma once or ifndef?
  • 很高兴知道投反对票的原因:)
  • 这是一个很好的解决方法,尽管我真的希望我的形状 ctor 只具有特定于它们自己的参数,例如 Circle(float radius, sf::Vector2f pos); 并且可以访问那些公共变量。如果我找不到这样做的方法,我可能会使用你的方法! ps:我把你带回了 0 哈哈
猜你喜欢
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多