【问题标题】:How to create and access a static object如何创建和访问静态对象
【发布时间】:2021-01-06 02:13:04
【问题描述】:

这是我得到的错误:

'global_grid' was not declared in this scope

Notator 类中的这一行(定义如下)导致错误: int option = global_grid.GetOption();.


Director 正在协调与网格一起工作的不同模块。我需要一个网格可供所有班级使用。我不希望它是一个单例,因为可以想象有多个网格。我不希望它属于Director 类,因为这在概念上对我来说没有意义。 Director 只是引导流量。

我认为global_grid(如下声明)会随处可见。我想我不明白static,或者可能是如何访问该对象。

没有导致错误的语句,项目编译。我错过了什么?

class SoundFile // This module has a grid that is needed by the other modules
{
    public:
        int GetOption(){ return 0; }
};

class Director //  Coordinates communication between modules
{
  public:   
      SoundFile& CreateGrid()
      {
        static SoundFile grid; // All modules need access to this grid.
        return grid;
      }
      
      void SetUp() // I want to call this when the app starts, to 
                       //create a global grid.
      {
        SoundFile& global_grid = CreateGrid(); // Would this create a static object? 
      }
};

class Notator // One of the modules that needs access to the grid
{
    public:
        void Work() 
        {   
           int option = global_grid.GetOption(); // Causes the error
        }
};

【问题讨论】:

  • 好的,让我看看链接上的信息
  • global_gridDirector::SetUp 中的本地标识符
  • 错误信息指的是global_grid。为什么你认为global_grid 是静态的?您使用static 关键字的唯一声明是grid
  • 实际上,这整个“静态”业务与您的错误无关。 (“静态”并不意味着“全局”。)再次阅读错误消息:“在此范围内声明”。为什么你认为global_grid(在Director::SetUp()内本地声明)是在发生错误的范围内声明的?

标签: c++ static singleton


【解决方案1】:

您似乎倾向于创建一个全局变量,该变量通常风格不佳,表明需要进行设计审查。我认为您的代码就是这种情况。但是,您的代码中有一些元素表明您的设计的某些部分在正确的轨道上。我会朝那个方向推进,但请理解这不是最终代码;在您审查和改进您的设计时,我期待进一步的调整。

一个好的方面是您将预期的“全局”网格作为Director 类的一部分。如果全局网格与Director 类有很强的关联,这比使用全局变量要好。也许不同的班级会是一个更合乎逻辑的选择;一旦你看到可以做什么,你就可以回顾一下。将“全局网格”作为SoundFile 类的一部分甚至可能是合理的。关键是可以在某个合适的名称(类或命名空间)下访问全局网格,而不是在全局范围内。

实际上,您所描述的大部分都是您想要的。您的CreateGrid() 函数创建了一个SoundFile 对象,即grid static local variable,第一次调用它时,随后的调用将返回对与前一次调用相同的对象的引用。 (这个名字有点奇怪,因为没有调用,但首先创建了一个网格。)这可能是你的全局网格,除了需要一个 Director 对象来调用这个函数。

将此函数声明为Directorstatic member 将在调用CreateGrid() 时消除对Director 对象的需要。此外,这样做是合乎逻辑的,因为该函数不使用调用它的对象(也就是函数内部的*this)。

class Director
{
  public:   
      static SoundFile& CreateGrid()  // <-- add the `static` keyword here
      {
        static SoundFile grid;        // <-- (and keep the `static` keyword here)
        return grid;
      }
};

没有必要尝试将此函数的返回值分配给“全局”变量。函数调用可以在您打算使用变量的任何地方使用。例如:

int main()
{
    std::cout << Director::CreateGrid().GetOption() << '\n';
}

这种方法与单例设计模式有一些相似之处,但这种方法并不禁止存在其他SoundFile 对象。这些对象中只有一个具有特殊名称,其生命周期与程序一样长。


请注意,您可以改为使 grid 成为 Director 类的静态数据成员。但是,从长远来看,成员函数方法有两个优点,您可能会从中受益。首先,成员函数改进了封装,因为调用者不需要确切知道SoundFile 对象是如何获得的。您可以更改实现而不需要在整个程序中更改代码。其次,使用成员函数有助于避免称为“static initialization order fiasco”的现象。

【讨论】:

  • 我很欣赏这些代码示例。毫无疑问,真正的问题是我的设计。我打算使该函数成为Director 的静态成员。然后我回顾了一些设计模式,结果证明中介模式是合适的。 Director 管理一组模块,通常这些模块需要网格。所以网格是Director 的成员。 Director 接受用户输入,然后调用适当的模块方法,将网格传递给它。并且模块在完成时通知Director
猜你喜欢
  • 1970-01-01
  • 2014-06-03
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多