2013-12-09 124 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方法。

相關問題