“全球”和“单身”的“事物”的全局变量?

时间:2013-04-07 07:40:44

标签: c++ design-patterns embedded microcontroller

在处理微控制器时,有些本质上是全局的 - 我正在考虑串行端口或其他接口等外围设备。还有外围设备不仅是全局的,而且只有一个(并且永远不会有更多) - 如外围控制核心时钟或中断控制器。这些外设确实具有某种全局状态(例如 - 核心时钟被设置为某种东西)并且反向计算这些值是低效的。

如果我希望我的程序很好地面向对象,我很难决定如何处理这些对象......全局变量不好看,这很明显,但我只是不知道(不够经验)我是否应该试图“隐藏”这些东西是全局的事实......例如“cin”或“stdout”也是全局的(让我们忽略这样一个事实,即在多线程应用程序中这些通常是线程特定的并且没有人隐藏...让我们坚持使用时钟发生器外设 - 只有一个,所以我可以使用单例反模式(;或者使类静态或只是让单个对象全局(这就是我所拥有的)通常已经完成),因为这个对象存储了当前的时钟设置,并且很多其他东西需要这个值 - 需要设置RTOS使用的系统定时器,需要为其他外设设置时钟(UART波特率,SPI比特率,。 ..),需要为外部存储器设置正确的时钟或配置存储器等待状态。这就是我认为的原因在main()中创建一个对象并在任何地方传递它的帽子会有点麻烦......

我可以编写方法,以便所有“全局”信息都来自外设寄存器(例如核心频率可以从当前的PLL设置反向计算),但这似乎也是错误的想法,更不用说了为时钟发生器外围设备创建对象看起来很有趣......

当前时钟设置可以存储在类的静态成员中,但是从这里开始,只有一小步朝向完全静态类(因为“this”指针对于没有状态的类是无用的)... < / p>

通常在非面向对象程序中找到的解决方案最接近完全静态类 - 只有对全局变量进行操作的函数。

任何人都知道如何很好地处理这种情况或者这个问题是否值得花时间?也许我应该只使用一个全局对象并完成它? (;

4 个答案:

答案 0 :(得分:5)

  

如果我希望我的程序很好地面向对象,我很难决定如何处理这些对象......全局变量不好看,这很明显,但我只是不知道(经验不足)我是否应该试图“隐瞒”这些东西是全球性的......

当我读到它时,我想知道你是否知道为什么使用OOP以及为什么不使用全局变量。

首先,OOP是一个工具,而不是目标。在您的情况下,中断控制器不需要派生和虚函数之类的东西。您需要的只是一个编程接口,包含在一个类中。您甚至可以使用一组执行该功能的简单函数(C =样式模块化编程),而不会放弃可维护性。在您的情况下,使单个实例全局化甚至更清晰。想象一下替代方案,程序的不同部分可以实例化一个用于访问下面相同UART的类。如果您正在使用全局变量,那么代码(或者更确切地说是作者)会意识到这一点,并会考虑如何协调访问。

现在,关于全局变量,这里有一个例子,为什么不使用它们:

int a, b, c;

void f1()
{
    c = a;
    f3();
}

void f2()
{
    c = b;
    f3();
}

void f3()
{
    // use c
}

int main()
{
    a = 4;
    f1();
    b = 5;
    f2();
}

这里的要点是参数存储在全局变量中,而不是将它们作为实际参数传递,并且很难看到参数的使用位置和时间。此外,上面的使用完全排除了任何递归调用。关于你的环境,有些东西本质上是全局的,因为它们是环境的独特部分,比如中断控制器(类似于cin / cout / cerr / clog)。不要担心那些。在您需要考虑限制访问权限之前,必须有很多这些地方使用过。

有两条指导原则可以让您更轻松:

  • 对象的范围越大,说出的名字就越多(与上面的a,b,c相比)。在您的情况下,我将所有特定于硬件的对象存储在一个公共命名空间中,因此很明显有些代码正在访问全局变量。这也允许单独测试和重用此命名空间。许多硬件供应商甚至以库的形式提供这样的东西,以帮助开发应用程序。
  • 在硬件的代码换行/建模中,执行请求但不要在其上做出特定于应用程序的决策。与例如比较标准流,提供但从未被标准库本身使用,除非在断言失败后中止之前转储致命错误信息。

答案 1 :(得分:2)

您已经概述了您的选择:

  • 全局
  • 类/单身人士的静态数据成员

最终由你决定两者之间,并从美学或其他方面选择你更喜欢的。

在一天结束时,就像你说的那样,你仍然会有一个时钟发生器,一个UART等。

要记住的一点是,仅仅为了抽象而过多的抽象并不会给你带来太大的收获。然而,它可能会使你的代码不熟悉的人更难以理解事物在各层之后的真正作用。因此,请考虑您的团队,如果有的话。

答案 2 :(得分:2)

单身人士模式肯定是辩论的源泉。有些人只是说它“不好”,但我不同意;它被广泛误用和误解。在某些情况下它绝对有用。事实上,它恰好适用于您所描述的情况。

如果您有一个需要全局可用的类,并且其本质上不能有多个实例,那么单例是最佳选项。

答案 3 :(得分:1)

单身人士,全球对象,静态类,他们都是一样的。在你想要的任何酱汁中装扮邪恶的全球状态,它仍然是全球状态。问题在于沙拉,而不是在沙拉中,可以这么说。

一个有点探索的路径是monadic代码,Haskell风格(在C ++中是的)。我自己从未尝试过,但从它的外观来看,这个选项应该很有趣。参见例如here用于C ++中Monad接口的示例实现。