4

一般来说,我是 C++ 和 OOP 的新手,一直在尝试学习有效或“正确”的做事方式,但仍然遇到麻烦。

我正在创建一个保存其他类/对象数据的 DataStore 类。这个类只会有一个实例/对象;但是,实际上并不需要对象/实例,因为它是全局数据,对。在这种情况下,我觉得这只是提供范围的一种方式。所以,我想直接更改类成员而不是传递对象。我已经阅读了有关静态和 _extern 的内容,但我无法确定其中一个是否可行,或者是否还有其他更好的方法。

现在我正在传递一个创建的对象以更改它的数据,但我宁愿将该类作为“自身”而不是“自身的实例”访问,同时仍然保留它是一个对象的想法。

4

4 回答 4

3

通常,这种问题(您需要一个,但只有一个 - 而且您确信您永远不需要更多)通过使用“单例”模式来解决。

class Singleton
{
  public:
    static Singleton* getInstance() 
    { 
       if (!instance) instance = new Singleton(); 
       return instance;
    }

    int getStuff() { return stuff; }


  private:
    Singleton() { stuff = 42; }
    static Singleton *instance;
    int stuff; 
};

然后在一些合适的 .cpp 文件中>

static Singleton *instance;

或者直接使用全局变量:

class Something
{
 public:
   Something() { stuff = 42; }

   int getStuff() { return stuff; }

 private:
   int stuff; 
}

extern Something global_something;    // Make sure everyone can find it. 

在一个 .cpp 文件中:

Something global_something; 

由于这两者本质上都是一个全局变量解决方案,我希望不喜欢全局变量的人会否决它,但如果你不想到处传递你的类对象,全局变量并不是一个糟糕的主意。您只需要知道全局变量作为一般解决方案不一定是一个好主意。很难了解正在发生的事情,如果您突然需要多个存储(因为您决定更改代码以支持两种不同的存储或其他),它肯定会变得混乱 - 但这也适用于单例。

于 2013-07-05T20:02:33.400 回答
1

编辑:在评论中,OP 解释了数据存储将由在多个线程中运行的代码读取,并由一个线程中的代码更新。我之前的回答不再适用。这是一个更好的答案。

不要使用全局变量来保存商店的实例。这将为许多可能困扰您很长时间的细微错误打开大门。您应该为您的阅读线程授予对商店的只读访问权限。您的写作线程应该获得读写访问权限。

确保数据存储中的读取方法正确标记为const. 然后创建数据存储的单个实例,并将指向它的指针放在const全局变量中。您的编写线程应该有另一种获取非常量指针的机制(添加一个GetInstance公共静态方法,如@Mats 所建议的那样)。

我之前的回答:如果您确定总是只有一个数据存储实例,请不要传递它。

全局变量不受欢迎,一些语言(Java 和 C#)完全禁止它们。因此,在 C# 和 Java 中,您使用静态类成员,它们实际上是相同的(具有完全相同的问题)。

如果你可以把你的单个实例放在一个const全局变量中,你应该没问题。

如果你在做任何类型的多线程,你需要确保你的存储是线程安全的,否则会发生非常糟糕的事情。

于 2013-07-05T19:53:02.620 回答
1

您可以使用有争议的 Singleton 模式,也可以使用Mark Radford (Overload Journal #57 – Oct 2003) SINGLETON 中描述的 PARAMETERISE FROM ABOVE 方法之一 - 反模式!文章。

PARAMETERISE FROM ABOVE 方法(在他看来)加强了封装并缓解了初始化困难。


经典的懒惰评估并正确销毁单例:

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {};                   // Constructor? (the {} brackets) are needed here.
        // Dont forget to declare these two. You want to make sure they
        // are unaccessable otherwise you may accidently get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement
};

但请注意:这不是线程安全的。

看到这里关于单例的好 StackOverflow 帖子

于 2013-07-05T20:13:37.067 回答
1

我为在程序执行期间大部分时间具有 1 个实例的对象执行此操作。

class Object {
private:
  Object();
  friend Object & GetObject();

public:
   ...
};

inline Object & GetObject() {
    static Object O;
    return O;
}

1)这比单例更简洁。
2)这避免了全局对象的陷阱,例如未定义的初始化顺序。

于 2013-07-05T20:21:25.703 回答