2013-12-09 50 views
0

我正在编写一些arduino代码,但事情并没有完全打算。
我在这里做错了什么?我已经阅读并试图教育自己关于虚拟功能,但也许我错过了一些东西。前往QUESTIONSHERE查看需要解答的实际问题,但首先需要解释一下:不像预期的那样运行多态类

RGBPixel类和colorGenerator类都是从colorSource派生的,它提供了公共函数getR(),getG()和getB()另一个像素或颜色修改器可以获取其当前颜色的副本。
从colorGenerator派生的类实现颜色生成代码,以便它们可以生成它们自己的颜色,而RGBPixels具有colorSource *父成员,因此它们可以从colorGenerator或另一个RGBPixel获取颜色值。
在我的例子中,我有一个colorGenerator子类(CG_EmeraldWaters,它应该为我创建各种绿色和蓝色),然后是数组中的一些RGBPixels。 RGBPixels [0]应从GC_EmeraldWaters的实例中获取其值,而RGBPixels [1]从[1],[n]中的[1],[n]的RGBPixels [0],[2]中获取其值。这些像素似乎是从父母那里拉出一种颜色,但是链中的第一个像素没有正确查询colorGenerator,或者colorGenerator没有正确更新。

要更新colorGenerator,一个colorController类监督的全过程:

colorController.h:

#ifndef _COLORCONTROLLER_H 
#define _COLORCONTROLLER_H 

#include <list> 
#include "colorGenerator.h" 
#include "RGBPixel.h" 
#include "globals.h" 
#include "Arduino.h" 

unsigned long millis(); 

typedef std::list<colorGenerator> generatorList; 

class colorController 
{ 
    public: 
    virtual bool refresh(); 
    protected: 
    generatorList generators; 
}; 

#endif //_COLORCONTROLLER_H 

正如你所看到的,控制器具有colorGenerators和方法刷新他们所有的列表(从循环中调用()),其除非在子类中重写,这是否:

bool colorController::refresh() 
{ 
    for (generatorList::iterator it = generators.begin(); it != generators.end(); ++it) 
    it->refresh(); 
    bool dirty = false; 
    for (int i = NUM_OF_LEDS-1; i >= 0; --i) 
    dirty |= RGBPixels[i].refresh(); 
    return dirty; 
} 

的CC_Cascade类(来自colorController衍生)组事情是这样的:

CC_Cascade.h

#ifndef _CC_CASCADE_H 
#define _CC_CASCADE_H 

#include "colorController.h" 

class CC_Cascade : public colorController 
{ 
    public: 
     CC_Cascade(); 
     ~CC_Cascade(); 
}; 

#endif //_CC_CASCADE_H 

CC_Cascade.cpp

#include "CC_Cascade.h" 
#include "CG_EmeraldWaters.h" 

CC_Cascade::CC_Cascade() 
{ 
    colorGenerator * freshBubblingSpring = new CG_EmeraldWaters(); 
    generators.push_back(*freshBubblingSpring); 
    RGBPixels[0].setParent(freshBubblingSpring); 
    RGBPixels[0].setDelay(40); 
    for (int i = 1; i < NUM_OF_LEDS; ++i) 
    { 
    RGBPixels[i].setParent(&RGBPixels[i-1]); 
    RGBPixels[i].setDelay(500-(9*i)); //FIXME: magic number only works for 50ish pixels 
    } 
} 

CC_Cascade::~CC_Cascade() 
{ 
    //TODO: delete generators 
} 

到目前为止清楚了吗? 让我把注意力放在colorController :: refresh()函数上。应该发生的是,每次调用时,生成器列表中都有一个colorGenerator(因为CC_Cascade构造函数将它放在那里),这是一个CG_EmeraldWaters。当对此(通过迭代器)调用refresh()时,它会调用colorGenerator :: refresh(),然后调用updateColor()。在CG_EmeraldWaters的情况下,这被覆盖,所以CG_EmeraldWaters :: updateColor应该被调用,给出一个绿松石的颜色。使用一些串行写入语句进行调试,我可以看到IN FACT colorGenerator :: updateColor()被调用,所以在这种情况下,我期望橙色的颜色,但这些都不影响像素的颜色,这些都是保持在CG_EmeraldWaters构造器中设置的紫色。
做了一些小事,我在colorGenerator :: updateColor()中添加了以下代码:RGBPixels[0].setColor(255,127,0); 而不是我希望的橙色,第一个像素在紫色和橙色之间快速交替,暗示(恕我直言)我的新代码行正在做它的工作,但是然后像素从colorGenerator中再次拉出其原始的紫色,并且不知怎的,colorGenerator :: updateColor()不会改变colorGenerator的颜色(因为我没有得到编译错误,它在改变什么?)。

所以我qustions是:(QUESTIONSHERE)
1)我怎样才能colorSource :: currentR(/ G/B)的值从colorGenerator :: updateColor(),因为内改变currentR(/ G/B)在colorSource中声明为受保护,并且colorGenerator直接从colorSource派生?
2)鉴于CG_EmeraldWaters的一个实例,如果updateColor()在colorGenerator中声明为虚拟并在CG_EmeraldWaters中重写,那么如何通过colorGenerator :: refresh()调用CG_EmeraldWaters :: updateColor(),CG_EmeraldWaters继承了CG_EmeraldWaters?

下面是colorGenerator和CG_EmeraldWaters的代码:

colorSource.h:

#ifndef _COLORSOURCE_H 
#define _COLORSOURCE_H 

#include "Arduino.h" 
#ifdef DEBUG 
#include "colorGenerator.h" //FIXME: delete Me 
#endif 

//#define byte unsigned char 
typedef byte colorStorage_t; 

class colorSource 
{ 
    public: 
    colorSource(); 
     colorSource(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB); 

    void setColor(colorStorage_t newR, colorStorage_t newG, colorStorage_t newB); 
    //TODO: better implementation than this 
    colorStorage_t getR(); 
    colorStorage_t getG(); 
    colorStorage_t getB(); 

    bool hasChanged(); 

    protected: 
    colorStorage_t currentR; 
    colorStorage_t currentG; 
    colorStorage_t currentB; 

    bool dirty; 
#ifdef DEBUG 
    friend colorGenerator; //FIXME: delete Me 
#endif 
}; 

#endif //_COLORSOURCE_H 

colorSource.cpp:

#include "colorSource.h" 

colorSource::colorSource() 
{ 
    //nothing here 
} 

colorSource::colorSource(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB) 
    : 
    currentR(initialR), 
    currentG(initialG), 
    currentB(initialB) 
{ 
    //intialised in the list 
    Serial.println("Constructed Color Source with initial color"); 
} 

void colorSource::setColor(colorStorage_t newR, colorStorage_t newG, colorStorage_t newB) 
{ 
    currentR = newR; 
    currentG = newG; 
    currentB = newB; 
} 

colorStorage_t colorSource::getR() 
{ 
    return currentR; 
} 

colorStorage_t colorSource::getG() 
{ 
    return currentG; 
} 

colorStorage_t colorSource::getB() 
{ 
    return currentB; 
} 

bool colorSource::hasChanged() 
{ 
    return !dirty; 
} 

colorGenerator.h:

#ifndef _COLORGENERATOR_H 
#define _COLORGENERATOR_H 

#include "colorSource.h" 
#ifdef DEBUG 
#include "RGBPixel.h" //delete me, used for debugging! 
#include "globals.h" //and me! 
#endif 

extern "C" unsigned long millis(); 

class colorGenerator : public colorSource 
{ 
    public: 
     colorGenerator(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB); 
    bool refresh(); 

    protected: 
    virtual void updateColor(); 

    unsigned long nextColorUpdate = 0; 
    unsigned short delay = 40; 
}; 

#endif //_COLORGENERATOR_H 

colorGenerator.cpp:

#include "Arduino.h" 

#include "colorGenerator.h" 

colorGenerator::colorGenerator(colorStorage_t initialR, colorStorage_t initialG, colorStorage_t initialB) 
    : 
    colorSource(initialR,initialG,initialB) 
{ 
    //intialised in the list 
    //Serial.println("Constructed Color Generator"); 
} 

bool colorGenerator::refresh() 
{ 
#ifdef DEBUG 
    Serial.print("colorGenerator::refresh()"); 
#endif 
    if (millis() < nextColorUpdate) 
    return false; 
    nextColorUpdate = millis() + (unsigned long) delay; 
    this->updateColor(); 
    return true; 
} 

void colorGenerator::updateColor() //this function gets called (even if it has been overridden in a child class), but the code in it doesn't have the desired effect 
{ 
#ifdef DEBUG 
    //Serial.print("colorGenerator::updateColor()"); 
    //RGBPixels[0].setColor(255,127,0); 
#endif 
    currentR = random(127,255); 
    currentG = random(0,127); 
    currentB = 0; 
} 

CG_EmeraldWaters.h:

#ifndef _CG_EMERALDWATERS_H 
#define _CG_EMERALDWATERS_H 

#include "colorGenerator.h" 
#include "globals.h" 
#include "RGBPixel.h" 

class CG_EmeraldWaters : public colorGenerator 
{ 
    public: 
     CG_EmeraldWaters(); 

    protected: 
     void updateColor(); 
}; 

#endif //_CG_EMERALDWATERS_H 

CG_EmeraldWaters.cpp:

#include "Arduino.h" 

#include "CG_EmeraldWaters.h" 

CG_EmeraldWaters::CG_EmeraldWaters() 
    : 
    colorGenerator(255,0,255) //this color seems to stick! Changes made by updateColor() aren't propogated to the pixels. 
{ 
    //initialised in list 
    //Serial.println("Constructed Emerald Waters"); 
} 

long random(long,long); 

void CG_EmeraldWaters::updateColor() //this never seems to be called! 
{ 
    currentR = 0; 
    currentG = random(0,255); 
    currentB = random(0,255); 
} 

最后,主要的素描文件:

#include "FastSPI_LED2.h" 
#include <StandardCplusplus.h> 

#include "colorController.h" 
#include "RGBPixel.h" 
#include "globals.h" 
#include "CC_Cascade.h" 

colorController * currentColorController; 
RGBPixel RGBPixels[NUM_OF_LEDS]; 
struct CRGB ledString[NUM_OF_LEDS]; 

void setup() 
{ 
#ifdef DEBUG 
    //debugging: 
    Serial.begin(9600); 
    Serial.println("In Setup"); 
#endif 

    // sanity check delay - allows reprogramming if accidently blowing power w/leds 
    //delay(2000); 
    LEDS.setBrightness(8); 
    LEDS.addLeds<WS2801>(ledString, NUM_OF_LEDS); 

    currentColorController = new CC_Cascade(); 
} 

void writeValuesToString() 
{ 
    for (int i = 0; i < NUM_OF_LEDS; ++i) 
    ledString[i] = CRGB(RGBPixels[i].getR(),RGBPixels[i].getG(),RGBPixels[i].getB()); 
    LEDS.show(); 
} 

void loop() 
{ 
    static bool dirty = false; //indicates whether pixel values have changed since last hardware write 
    //unsigned long lastHardwareWrite = 0; //time of last hardware write - only do this once per milisecond to avoid flicker (this method doesn't work, still flickers) 

    dirty |= currentColorController->refresh(); 
    if (dirty) 
    { 
    dirty = false; 
    writeValuesToString(); 
     delay(1); //to prevent flicker 
    } 
} 
+0

1。你应该能够从它的子类中调用超类的私有和受保护的方法,除非我错过了某些东西。 – splrs

+0

这个问题太大了 - 我很想在第一个代码片段后停止阅读,但幸运的是我发现顶部的问题。一般来说,你应该尝试建立一个小的(最好是微小的)独立的示例来显示问题。 – dasblinkenlight

回答

5

你问题是由于所谓的呼叫ed object slicing。这里是正在发生的事情:当你声明generatorList

typedef std::list<colorGenerator> generatorList; 

其成员被限制到什么是colorGenerator类型的列表。从派生类的事项没有什么,所以当你把

colorGenerator * freshBubblingSpring = new CG_EmeraldWaters(); 
generators.push_back(*freshBubblingSpring); 

CG_EmeraldWaters部分,是不是也colorGenerator被“切掉”;你最终得到的版本是colorGenerator

原因在上面链接的维基百科文章中描述。要解决此问题,请将列表更改为包含指针,最好是smart pointers,指向colorGenerator实例。然后切割问题将不再是相关的:

typedef std::list<unique_ptr<colorGenerator> > generatorList; 
... 
unique_ptr<colorGenerator> freshBubblingSpring(new CG_EmeraldWaters()); 
generators.push_back(freshBubblingSpring); 
+0

谢谢,我要问我该如何实现它,然后你用一个例子编辑!只是googling unique_ptr - 我想知道我将如何尊重迭代器。我需要**双重尊重吗?现在看看我是否有unique_ptr可用... –

+0

@M_M'std :: unique_ptr' [覆盖' - >'和'*'运算符](http://en.cppreference.com/w/cpp/memory/unique_ptr/operator *)来提供对底层对象的访问。所以你可以使用两个星号,或者用星号和“箭头” - >'来加倍解引用。 – dasblinkenlight

+0

我没有unique_ptr可用(我使用的STL头文件不是C++ 11),但我对普通指针非常满意,特别是因为我在arduino板上略有空间限制。我用'** it.refresh();','* it-> refresh();'和'it - > * refresh()'得到了编译错误,所以我使用了'{colorGenerator * thisGenerator = * it ; thisGenerator->刷新();}'。直到明天我才能访问目标硬件,看看它是否有效,但我会让你知道的!与此同时,任何人都可以想到句法上正确的一行? –

0
  1. 您应该能够从派生类中调用基类的私有和保护方法,除非我失去了一些东西。要调用超类方法(例如virtual class foo()在Base类中定义并在Derived类中重写),可以通过在代码中调用derivedObj.Base::foo()来访问Base方法。

相关问题