在 class 函数中初始化外部作用域变量

Initialize outer scope variable in class function

我是 C++ 新手,我有 C# 背景。由于 https://docs.platformio.org/ .

,我正在使用 VS 代码使用 C++ 创建一个 Arduino 项目

以下代码可以工作并打开我的 LED 灯条:

main.cpp

#include <Arduino.h>   
#include <LedStrip.h>

// pin where led strip is connected
#define LED_STIP_PIN 4

// number of leds in the strip
#define LED_STRIP_COUNT 7

// My wrapper class
LedStrip myLedStripWrapper;


void setup() {
   // empty
}

void loop() {
   
    myLedStripWrapper.setup(LED_STRIP_COUNT, LED_STIP_PIN);

    // myLedStripWrapper.foo1();  // <<<HERE-1>>>
    
    // wait forever
    while (true) {
        delay(1);
    }       
}

LedStrip.h

#include <Adafruit_NeoPixel.h>

class LedStrip
{

public:
    
    Adafruit_NeoPixel strip;

    void setup(uint16_t led_count, uint16_t pin)
    {
        // Declare our NeoPixel strip object:
        Adafruit_NeoPixel a(led_count, pin, NEO_GRB + NEO_KHZ800);                
        strip = a;

        // INITIALIZE NeoPixel strip
        strip.begin();            
        strip.show();            
        strip.setBrightness(15); 

        foo1();     // <<<HERE-2>>> <------------------- calling foo1 from here turns on the led strip           
    }

    
    // Color led strip blue
    void foo1()
    {
        uint32_t color = strip.Color(0, 0, 100);
        for (uint16_t i = 0; i < strip.numPixels(); i++)
        {                                  // For each pixel in strip...
            strip.setPixelColor(i, color); //  Set pixel's color (in RAM)
            strip.show();                  //  Update strip to match
            // delay(100);
        }
    }
};

请注意,在代码中我有标签 <<<HERE-1>>><<<HERE-2>>>。我想从 <<<HERE-1>>> 调用函数 foo1为什么如果我取消注释 <<<HERE-1>>> 并注释 <<<HERE-2>>> 代码不起作用并且 LED 灯条不亮? 换句话说我不想从 class 包装器中调用 foo1。我只是从那里调用它,因为它只有在我从那里调用它时才有效。

那个 class 的作者犯了一个小学 C++ 错误,没有正确观察 Rule of Three。这意味着可以在不安全的情况下复制 Adafruit_NeoPixel 对象。

void setup(uint16_t led_count, uint16_t pin)
{
    // Declare our NeoPixel strip object:
    Adafruit_NeoPixel a(led_count, pin, NEO_GRB + NEO_KHZ800);                
    strip = a; // copy here. Both a and strip point to a shared resource

    // INITIALIZE NeoPixel strip
    strip.begin();            
    strip.show();            
    strip.setBrightness(15); 
} // a goes out of scope here and frees the shared resource in its 
  // destructor. Oops.

最简单的解决方法是在 LedStrip 的构造函数中初始化 strip,而无需复制它。

为了确保 strip 不被复制,您将不得不阻止 LedStrip 被复制或实现允许 LedStrip 被复制而不复制的特殊成员函数strip。在下面的示例中,我将简单地防止复制。

如果需要复制,请考虑将 Adafruit_NeoPixel strip; 替换为 std::shared_ptr<Adafruit_NeoPixel> strip;,以便复制指针而不是复制时会变成炸弹的对象。

class LedStrip
{

public:
    
    Adafruit_NeoPixel strip; // you sure you want this public?
    //  adding constructor so we don't have to copy a Adafruit_NeoPixel  object
    LedStrip(uint16_t led_count, uint16_t pin): 
        strip(led_count, pin, NEO_GRB + NEO_KHZ800) // this is a member initializer list
                                                    // It allows us to construct strip 
                                                    // without having to copy anything.
                                                    // more on that later
    {
        // INITIALIZE NeoPixel strip
        strip.begin();            
        strip.show();            
        strip.setBrightness(15); 
    }

    // preventing copying of LedStrip
    LedStrip(const LedStrip& ) = delete;
    LedStrip & operator=(const LedStrip& ) = delete;
    // note if the compiler doesn't like the = delete, remove it, make 
    // the copy constructor and assignment operator private, and do not 
    // implement them

    
    // Color led strip blue
    void foo1()
    {
        uint32_t color = strip.Color(0, 0, 100);
        for (uint16_t i = 0; i < strip.numPixels(); i++)
        {                                  // For each pixel in strip...
            strip.setPixelColor(i, color); //  Set pixel's color (in RAM)
            strip.show();                  //  Update strip to match
            // delay(100);
        }
    }
private:
/* only needed if the = delete trick above doesn't work.
    LedStrip(const LedStrip& );
    LedStrip & operator=(const LedStrip& );
*/
};

然后

LedStrip myLedStripWrapper;

变成

LedStrip myLedStripWrapper(LED_STRIP_COUNT, LED_STIP_PIN);

myLedStripWrapper.setup(LED_STRIP_COUNT, LED_STIP_PIN);

从世界上消失,再也不会出现。

Documentation on the Member Initializer List.

Documentation on std::shared_ptr