I am currently making a program in Arduino IDE to make animations with LEDs. My concept is that there is a base Animation class that holds the static RGBLed object that allows me to light up LEDs in the draw() method. All the children of Animation are supposed to inherit this object and the method. This is my Animation.cpp:
#include <RGBLed.h>
const int GPIN = D0, RPIN = D1, BPIN = D2; //RGB MOSFET pins
class Animation{
protected:
int R = 0, G = 0, B = 0;
static RGBLed myLED;
public:
void update(int currentTime){}
void draw(){
myLED.setColor(R, G, B);
}
};
RGBLed Animation::myLED(RPIN, GPIN, BPIN, RGBLed::COMMON_CATHODE);
class Animation1: public Animation{
private:
int timer = 0;
int anim_time = 1000;
public:
Animation1(){
timer = millis();
}
void update(int currentTime){
//do some RGB magic
}
}
};
class RGBSwipe: public Animation{
private:
float H = 0.0, S = 1.0, V = 1.0;
int timer = 0;
int delay_time = 10;
public:
RGBSwipe(){
timer = millis();
}
void update(int currentTime){
//do some HSV magic
}
}
private:
void HSVtoRGB(){
//Conversion happens here
}
};
I get this error:
(USER)/appdata/local/arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/bin/../lib/gcc/xtensa-lx106-elf/10.3.0/../../../../xtensa-lx106-elf/bin/ld.exe: (USER)\AppData\Local\Temp\arduino-sketch-3EC4D14CA84EC5BABE4C744AA5D32B6B\sketch\FFT_analyzer.ino.cpp.o:(.bss._ZN9Animation5myLEDE+0x0): multiple definition of `_ZN9Animation5myLEDE'; (USER)\AppData\Local\Temp\arduino-sketch-3EC4D14CA84EC5BABE4C744AA5D32B6B\sketch\Animation.cpp.o:(.bss._ZN9Animation5myLEDE+0x0): first defined here collect2.exe: error: ld returned 1 exit status
exit status 1
Compilation error: exit status 1
I tried re-locating the definition but nothing seems to work. Any Ideas?
In your main.cpp
, you have a #include "Animation.cpp"
.
Don't do that.
Never #include
an implementation .cpp
file, only header files .h
or .hpp
. There are exceptions to that rule for advanced uses, like creation of an amalgamation, but this is only for expert C++ programmers.
All .cpp
files shall be compiled separately. This is what is called a compilation unit. In your situation, the content of Animation.cpp
was compiled twice, once for its own and once inside main.cpp
. Ans the linker has two copies for each identifier.
This is not a problem for the class declarations (they should indeed be declared in shared header files). This is not a problem neither for the function member definitions, since as they are placed inside the class
block, are implicitly inline
.
It happens this is not a problem neither with GPIN
, RPIN
and BPIN
variables. As they are declared const
at global scope, they are implicitly static
, meaning there is one distinct copy per compilation unit (usually compiled out by the optimizer however).
But RGBLed Animation::myLED(RPIN, GPIN, BPIN, RGBLed::COMMON_CATHODE);
is a definition, which must be defined once to follow the One Definition Rule (ODF).
So move most of your code into Animation.h
, and #include "Animation.h"
into both main.cpp
and Animation.cpp
. The definition of Animation::myLED
must be in Animation.cpp
and not in header. Also, I suggest to move the code marked // do some magic
out of the class
declaration into the implementation .cpp
file. Better reserve inline
methods to small functions like getters and setters. Also, prefer constexpr
to declare constant values instead of old const
.