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

Initialize outer scope variable in class function

本文关键字:作用域 变量 外部 初始化 类函数      更新时间:2023-10-16

我是新手C++因为我来自C#背景。由于 https://docs.platformio.org/,我正在使用 vs 代码使用 c++ 创建一个 Arduino 项目。

以下代码有效并打开我的 LED 灯条:

主.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 灯条无法打开?换句话说,我不想从类包装器中调用 foo1。我只是在那里称它为形式,因为它只有在我在那里称它为形式时才有效。

该类的作者犯了一个小学C++错误,没有正确遵守三法则。这意味着可以在不安全的情况下复制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.

最简单的解决方法是在不需要复制的构造函数中初始化LedStripstrip

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

如果需要复制,请考虑将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);

从世界上消失,再也看不到了。

有关成员初始值设定项列表的文档。

有关std::shared_ptr的文档