摆脱库中的全局变量

Posted

技术标签:

【中文标题】摆脱库中的全局变量【英文标题】:Get rid of global variables in library 【发布时间】:2017-02-03 12:20:02 【问题描述】:

我正在开发一个 MIDI 控制器库,它有几个类(例如,一类用于按钮,一类用于电位计,一类用于旋转编码器等)。所有这些类都有使用 sendMIDI 函数的方法。还有一个 setupMIDI 函数,在程序开始时调用一次。 setupMIDI 接受三个参数,需要通过 sendMIDI 函数访问。

类的定义

class Analog 
public:
  Analog (...)  ... 
  void refresh () 
    ...
    sendMIDI(x, y, z, ...);
    ...
  


class Digital  ... (also uses sendMIDI) ... 
etc.

setupMIDI 和 sendMIDI 函数

byte pin;
int delayTime;
bool debug;

void setupMIDI (byte p, int d, bool db = false) 
  ...
  pin = p; delayTime = d; debug = db;
  ...

void sendMIDI ( ... ) 
  ...
  if(debug) ...
  digitalWrite(pin, 1);
  delay(delayTime);
  ...

实际程序:

Analog a1( ... );
Analog a2( ... );
Digital d1( ... );

setupMIDI(13, 10, true);

while(true) 
  a1.refresh(); // calls sendMIDI
  a2.refresh();
  d1.refresh();

如您所见,Analog 和 Digital 类的所有实例都使用相同的 sendMIDI 函数,这取决于在 setupMIDI 函数中输入的值。问题是这些值存储在全局变量中,并不理想。

我曾考虑过使用 MidiSender 类,但这需要将它的一个实例传递给每个 Analog 或 Digital 构造函数。

有没有更好的方法来解决这个问题?

非常感谢! 彼得

【问题讨论】:

您能否澄清一下这种说法:“[...] in global variables, which is not Ideal”?我同意下面的答案,将所有变量包装在一起的 context 肯定更好,但我不明白为什么全局声明它并通过引用传递它比简单地将它作为全局可访问更好静态资源,至少在它应该是一个单例的情况下。例如,同样的解决方案适用于Serial.begin(...) 问题是如果用户尝试创建一个pin 变量,库将无法工作。你能指出一个关于如何实现像串行这样的东西的链接吗?或者也许是一些搜索词?谢谢! 好吧,您可以使用 namespaces 来解决名称冲突,imho 这更多的是 good design 实践在同一 contextinstance 中正确封装相关变量。但是,如果你的 midi 是一个 singleton,那么我看不出它是一个 global 有什么不好唯一的 实例。 Serial 的示例很容易理解,请查看“HardwareSerial0.cpp”中的声明(第 67-71 行)和“HardwareSerial.h/.cpp”中的类实现。 github上提供源代码:github.com/arduino/Arduino 【参考方案1】:

不要使用设置一些全局变量的setupMIDI 函数,而是使用MIDIContext 类来存储这些值并通过其构造函数对其进行初始化。

pindelayTimedebug 的用户要么是MIDIContext方法,要么采用MIDIContext& (在适当的情况下使用const& em> 访问值。

例子:

class MIDIContext

private:
    byte pin;
    int delayTime;
    bool debug;

public:
    MIDIContext(byte x_pin, int x_delayTime, bool x_debug) 
        : pinx_pin, delayTimex_delayTime, debugx_debug
    
    

    void sendMIDI();
;

class Analog

    void refresh (MIDIContext& ctx);
;

可能的用法:

Analog a1( ... );
Analog a2( ... );
Digital d1( ... );

MIDIContext context(13, 10, true);

while(true) 
  a1.refresh(context);
  a2.refresh(context);
  d1.refresh(context);

【讨论】:

谢谢!我只是想知道是否有更简单的方法,而不必将上下文作为参数传递,但这似乎确实是最直接的方法。 这项技术对确保代码线程安全大有帮助。

以上是关于摆脱库中的全局变量的主要内容,如果未能解决你的问题,请参考以下文章

C++ 静态库中的共享全局变量

C++ 静态库中的共享全局变量:Linux

C: 为啥我的库中的全局变量不会更新? (使用 ALSA 库)

如何在运行时确定共享库中全局变量的地址范围?

Javascript 和 ESLint 中的全局变量

如何清除或删除 Julia 中的全局变量?