Marc
Marc

Reputation: 2083

C++ class inherance, undefined reference to base class member fuction

I am just learning c++ and am having trouble with inheritance, comming from a c# background I feel C++ inhertance to be a little more complicated.

I have a base class UserInterface that has virtual and pure virtual methods :

class UserInterface
{
 protected:
    LiquidCrystal* lcd;

const int ICON_WATER_DROP = 0;
const int ICON_SMILEY = 1;
const int ICON_STATION = 2;
const int ICON_WATER_DROPS = 3;
const int ICON_ALARM = 4;
const int ICON_PRESSURE = 5;

/* icon for water drop */
byte waterDrop[8] =
{
        B00100,
        B00100,
        B01010,
        B01010,
        B10001,
        B10001,
        B10001,
        B01110
};

byte bucket[8] =
{
        B01010,
        B00100,
        B00010,
        B11111,
        B10001,
        B11111,
        B10001,
        B11111
};

/* smiley face */
byte smiley[8] =
{
        B00000,
        B10001,
        B00000,
        B00000,
        B10001,
        B01110,
        B00000,
        B00000
};

byte station[8] =
{
        B11110,
        B10010,
        B11111,
        B10011,
        B10011,
        B10011,
        B10010,
        B11111
};

byte alarm[8] =
{
        B00000,
        B00100,
        B01110,
        B01110,
        B01110,
        B11111,
        B00100,
        B00000
};

byte pressure[8] =
{
        B00100,
        B01110,
        B11111,
        B00100,
        B00100,
        B11111,
        B01110,
        B00100
};
public:
UserInterface();
virtual ~UserInterface();

virtual void drawIcon(int icon);
virtual void drawInitializingScreen();
virtual void clearScreen();
virtual void drawText(const __FlashStringHelper *line1);
virtual void drawText(const __FlashStringHelper *line1, const __FlashStringHelper *line2);
virtual void drawText(const __FlashStringHelper *line1, int line2);
virtual void drawAddressSetupScreen(int address);

// All this methods need to be implemented by each subclass
virtual void drawHomeScreen(byte address) = 0;
virtual void drawWateringTotalVolumeScreen(char* remainingTime, char* litres) = 0;
virtual void drawWateringVolumePerMinuteScreen(char* remainingTime, char* litres) = 0;
virtual void drawWateringPressureScreen(char* remainingTime, char* presure) = 0;
virtual void drawWateringPausedScreen(char* remainingTime) = 0;
virtual void drawWateringPausedAlternateScreen(char* remainingTime) = 0;
virtual void drawOutOfService(byte address) = 0;
virtual void drawInvalidSelection() = 0;
};

and the class implementation:

   UserInterface::UserInterface()
{
    //lcd = new LiquidCrystal(12, 11, 5, 4, 3, 2);
    lcd = new LiquidCrystal(5, 6, 7, 8, 9, 10);
    lcd->clear();

    // create a new custom characters
    lcd->createChar(ICON_WATER_DROP, waterDrop);
    lcd->createChar(ICON_SMILEY, smiley);
    lcd->createChar(ICON_STATION, station);
    lcd->createChar(ICON_WATER_DROPS, bucket);
    lcd->createChar(ICON_ALARM, alarm);
    lcd->createChar(ICON_PRESSURE, pressure);
}

UserInterface::~UserInterface()
{

}

void UserInterface::drawIcon(int icon)
{
    // print the custom char to the lcd
    lcd->write(icon);
}

void UserInterface::drawInitializingScreen()
{
    lcd->setCursor(0, 0);
    lcd->print(F("INICIALIZANDO"));
    lcd->setCursor(0, 1);
    lcd->print(F("VER:"));
    lcd->setCursor(5, 1);
    lcd->print(__DATE__);
}

void UserInterface::clearScreen()
{
    lcd->clear();
}

void UserInterface::drawText(const __FlashStringHelper *line1)
{
    lcd->setCursor(0, 0);
    lcd->print(line1);
}

void UserInterface::drawText(const __FlashStringHelper *line1, const __FlashStringHelper *line2)
{
    lcd->setCursor(0, 0);
    lcd->print(line1);
    lcd->setCursor(0, 1);
    lcd->print(line2);
}

void UserInterface::drawText(const __FlashStringHelper *line1, int line2)
{
    lcd->setCursor(0, 0);
    lcd->print(line1);
    lcd->setCursor(0, 1);
    lcd->print(line2);
}

void UserInterface::drawAddressSetupScreen(int address)
{
    lcd->setCursor(0, 0);
    lcd->print(F("ADDRESS SETUP"));
    lcd->setCursor(0, 1);
    lcd->print(address);
}

and a subclass :

class LCD16x2: public UserInterface
{
public:
    LCD16x2();
    ~LCD16x2();

    void drawIcon(int icon);
    void drawInitializingScreen();
    void clearScreen();
    void drawText(const __FlashStringHelper *line1);
    void drawText(const __FlashStringHelper *line1, const __FlashStringHelper *line2);
    void drawText(const __FlashStringHelper *line1, int line2);
    void drawAddressSetupScreen(int address);

    // All this methods need to be implemented by each subclass
    void drawHomeScreen(byte address) override;
    void drawWateringTotalVolumeScreen(char* remainingTime, char* litres) override;
    void drawWateringVolumePerMinuteScreen(char* remainingTime, char* litres) override;
    void drawWateringPressureScreen(char* remainingTime, char* presure) override;
    void drawWateringPausedScreen(char* remainingTime) override;
    void drawWateringPausedAlternateScreen(char* remainingTime) override;
    void drawOutOfService(byte address) override;
    void drawInvalidSelection() override;
};

and the implementation :

LCD16x2::LCD16x2()
{
    lcd->begin(16, 2);
}

LCD16x2::~LCD16x2()
{

}

void LCD16x2::drawHomeScreen(byte address)
{
    lcd->setCursor(0, 0);
    lcd->print(" HUERTOS DE OCIO");

    lcd->setCursor(0, 1);
    lcd->write(ICON_STATION);

    lcd->setCursor(3, 1);
    lcd->print(F("ESTACION "));
    lcd->print(address);
}

void LCD16x2::drawWateringTotalVolumeScreen(char* remainingTime, char* volume)
{
    lcd->setCursor(0, 0);
    lcd->print(F("RIEGO EN CURSO"));

    lcd->setCursor(0, 1);
    lcd->write(ICON_ALARM);
    lcd->setCursor(1, 1);
    lcd->print(remainingTime);

    lcd->setCursor(10, 1);
    lcd->write(ICON_WATER_DROP);
    lcd->setCursor(11, 1);
    lcd->print(volume);
}

void LCD16x2::drawWateringVolumePerMinuteScreen(char* remainingTime,
        char* volumePerMinute)
{
    lcd->setCursor(0, 0);
    lcd->print(F("RIEGO EN CURSO"));

    lcd->setCursor(0, 1);
    lcd->write(ICON_ALARM);
    lcd->setCursor(1, 1);
    lcd->print(remainingTime);

    lcd->setCursor(10, 1);
    lcd->write(ICON_WATER_DROPS);
    lcd->setCursor(11, 1);
    lcd->print(volumePerMinute);
}

void LCD16x2::drawWateringPressureScreen(char* remainingTime, char* pressure)
{
    lcd->setCursor(0, 0);
    lcd->print(F("RIEGO EN CURSO"));

    lcd->setCursor(0, 1);
    lcd->write(ICON_ALARM);
    lcd->setCursor(1, 1);
    lcd->print(remainingTime);

    lcd->setCursor(10, 1);
    lcd->write(ICON_PRESSURE);
    lcd->setCursor(11, 1);
    lcd->print(pressure);
}

void LCD16x2::drawWateringPausedScreen(char* remainingTime)
{
    lcd->setCursor(0, 0);
    lcd->print(F("RIEGO EN PAUSA"));
    lcd->setCursor(0, 1);
    lcd->print(remainingTime);
}

void LCD16x2::drawWateringPausedAlternateScreen(char* remainingTime)
{
    drawWateringPausedScreen(remainingTime);
}

void LCD16x2::drawOutOfService(byte address)
{
    lcd->setCursor(3, 0);
    lcd->print(F("ESTACION "));
    lcd->print(address);
    lcd->setCursor(0, 1);
    lcd->print(F("FUERA DE SERVICIO"));
}

void LCD16x2::drawInvalidSelection()
{
    lcd->setCursor(0, 1);
    lcd->print(F("SELECCION"));
    lcd->setCursor(0, 2);
    lcd->print(F("INVALIDA"));
}

The problem is that the compiler can't seem to accepts calls being made to the virtual methods implemented in the base class :

C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x8e): undefined reference to LCD16x2::drawIcon(int)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x90): undefined reference toLCD16x2::drawInitializingScreen()' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x92): undefined reference to LCD16x2::clearScreen()' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x94): undefined reference toLCD16x2::drawText(__FlashStringHelper const*)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x96): undefined reference to LCD16x2::drawText(__FlashStringHelper const*, __FlashStringHelper const*)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x98): undefined reference toLCD16x2::drawText(__FlashStringHelper const*, int)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans2.ltrans.o:(.rodata+0x9a): undefined reference to LCD16x2::drawAddressSetupScreen(int)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans3.ltrans.o: In functionupdateFirmwareCommand(unsigned char*, unsigned char*, unsigned char*)': C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:1149: undefined reference to LCD16x2::clearScreen()' C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:1152: undefined reference toLCD16x2::drawText(__FlashStringHelper const*, __FlashStringHelper const*)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans3.ltrans.o: In function selfTest': C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:693: undefined reference toLCD16x2::clearScreen()' C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:704: undefined reference to LCD16x2::drawText(__FlashStringHelper const*, int)' C:\Users\marcp\AppData\Local\Temp\ccjzyoeN.ltrans3.ltrans.o: In functionupdateLCD(bool)': C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:160: undefined reference to LCD16x2::clearScreen()' C:\Users\marcp\Dropbox\Source\RiegoMatic\HDO.RiegoMatic.Station.Firmware\Release/..\RMStationFirmware.cpp:169: undefined reference toLCD16x2::drawInitializingScreen()' collect2.exe: error: ld returned 1 exit status makefile:89: recipe for target 'RMStationFirmware.elf' failed make: *** [RMStationFirmware.elf] Error 1

Upvotes: 0

Views: 520

Answers (1)

grapes
grapes

Reputation: 8636

  1. ~LCD16x2() should be virtual.
  2. Do not redeclare methods in derived class, if you are not going to override them. Just remove their declaration from LCD16x2. If you are overriding, declare them as virtual in both base and derived class.

Upvotes: 1

Related Questions