Undefined reference to `vtable for "abstract classname" even after derived class definition

I'm working on a target shooting game where every target contains 2 leds and a piezo sensor (to register hits and it worked perfectly). This game will have multiple game modes based on the gamemode class (object) selected (each of them are children of a Gamemode cabstract clas with virtual functions that are overridden in the subclass definitions.

When i compile the code. I get this error which indicates that i'm trying to use undefines virtual methods.

C:\Users\PC\AppData\Local\Temp\ccEx1BKF.ltrans0.ltrans.o: In function `Gamemode::Gamemode()':
C:\Users\PC\Desktop\sketch_jan18a/Gamemode.h:12: undefined reference to `vtable for Gamemode'
C:\Users\PC\Desktop\sketch_jan18a/Gamemode.h:12: undefined reference to `vtable for Gamemode'
C:\Users\PC\AppData\Local\Temp\ccEx1BKF.ltrans0.ltrans.o: In function `global constructors keyed to 65535_0_GameHandler.cpp.o.2003':
<artificial>:(.text.startup+0x132): undefined reference to `vtable for Gamemode'
<artificial>:(.text.startup+0x134): undefined reference to `vtable for Gamemode'
C:\Users\PC\AppData\Local\Temp\ccEx1BKF.ltrans0.ltrans.o: In function `handleTargetsLogic':
C:\Users\PC\Desktop\sketch_jan18a/GameHandler.cpp:39: undefined reference to `Gamemode::prepareTargetHandler(Target&)'
C:\Users\PC\Desktop\sketch_jan18a/GameHandler.cpp:41: undefined reference to `Gamemode::onTargetHitHandler(Target&)'
collect2.exe: error: ld returned 1 exit status

exit status 1

Compilation error: exit status 1

Following snippets are the Gamemode header file:

#ifndef GAMEMODE_H
#define GAMEMODE_H
#include <stdlib.h>
#include <Arduino.h>
#include "Target.h"
#include "TargetState.h"

// enum Gamemode { SOLO_TIME_CHALLENGE,
//                 SOLO_RANDOM_CHALLENGE,
//                 MULTI_RANDOM_CHALLENGE };

class Gamemode {
protected:
  unsigned long startTime;
  unsigned long endTime;

  int ledOneThreshold;
  int ledTwoThreshold;
  int ledAllThreshold;
  int ledNonThreshold;

public:
  virtual void handleGameModeLogic();
  virtual void onTargetHitHandler(Target &target);
  virtual void prepareTargetHandler(Target &target);

};


#endif

subclass (Solotimemode.h and Solotimemode.cpp) files:

#ifndef SOLOTIMEMODE_H
#define SOLOTIMEMODE_H
#include <stdlib.h>
#include <Arduino.h>
#include "Gamemode.h"
#include "Target.h"

class SoloTimeMode : public Gamemode {
private:
  int _score;
  int _numTargets;



public:
  SoloTimeMode(int numTargets);
  void handleGameModeLogic() override;

  void prepareTargetHandler(Target &target) override;
  void onTargetHitHandler(Target &target) override;

  void endGame();
};

#endif

#include <stdlib.h>
#include <Arduino.h>
#include "SoloTimeMode.h"

SoloTimeMode::SoloTimeMode(int numTargets) {
  _score = 0;
  startTime = millis();
  endTime = 0;
  _numTargets = numTargets;

  ledOneThreshold = 0;
  ledTwoThreshold = 0;
  ledAllThreshold = 0;
  ledNonThreshold = 0;
}

void SoloTimeMode::handleGameModeLogic() {
}

void SoloTimeMode::prepareTargetHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      target.setState(LED_ONE);
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      break;
    case LED_ALL:
      break;
  }
}
void SoloTimeMode::onTargetHitHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      // do nothing
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      // _score++;
      target.setState(LED_TWO);
      _score++;
      if (_score == _numTargets) { endGame(); }
      break;
    case LED_ALL:
      break;
  }
}

void SoloTimeMode::endGame() {
  endTime = millis();
}

and finally, the gamehandler.cpp file which will be the class that uses the gamemode:

#include "GameHandler.h"
#include <stdlib.h>
#include <Arduino.h>

GameHandler::GameHandler(Target targets[], int numTargets, Gamemode mode) {
  _targets = targets;
  _numTargets = numTargets;
  _isPaused = true;
  _gameEnded = false;
   _gamemode = mode;



  _gameTimer = 0;
}

void GameHandler::init() {
  for (int i = 0; i < _numTargets; i++) {
    _targets[i].init();
  }
}

void GameHandler::selectGamemode(Gamemode mode) {
  _gamemode = mode;
  _isPaused = false;
  _gameTimer = millis();
}

void GameHandler::gameLoop() {
  if (_isPaused) {
    return;
  }

  handleTargetsLogic();
}

void GameHandler::handleTargetsLogic() {
  for (int i = 0; i < _numTargets; i++) {
    _gamemode.prepareTargetHandler(_targets[i]);
    if (_targets[i].hasBeenShot()) {
      _gamemode.onTargetHitHandler(_targets[i]);
    }
  }
}

Keep in mind that I'm not really used to c++ imports and i'm not really sure if im doing class abstraction correctly here.

This is the file. You can see the error when you try to compile it for an arduino uno

Are they pure virtual?

Try

  virtual void handleGameModeLogic()  = 0;
  virtual void onTargetHitHandler(Target &target) = 0;
  virtual void prepareTargetHandler(Target &target) = 0;

Post files here, very few of us (esp. reading on a mobile device) will go check stuff on a Google drive or outside the forum

I made your changes and now im getting the following error:

In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\sketch_jan18a.ino:2:0:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:27:32: error: cannot declare parameter 'mode' to be of abstract type 'Gamemode'
   void selectGamemode(Gamemode mode);
                                ^~~~
In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:6:0,
                 from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\sketch_jan18a.ino:2:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:12:7: note:   because the following virtual functions are pure within 'Gamemode':
 class Gamemode {
       ^~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:23:16: note: 	virtual void Gamemode::handleGameModeLogic()
   virtual void handleGameModeLogic()=0;
                ^~~~~~~~~~~~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:24:16: note: 	virtual void Gamemode::onTargetHitHandler(Target&)
   virtual void onTargetHitHandler(Target &target)=0;
                ^~~~~~~~~~~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:25:16: note: 	virtual void Gamemode::prepareTargetHandler(Target&)
   virtual void prepareTargetHandler(Target &target)=0;
                ^~~~~~~~~~~~~~~~~~~~
In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\sketch_jan18a.ino:2:0:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:18:12: error: cannot declare field 'GameHandler::_gamemode' to be of abstract type 'Gamemode'
   Gamemode _gamemode;
            ^~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\sketch_jan18a.ino: In function 'void setup()':
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\sketch_jan18a.ino:32:34: error: cannot allocate an object of abstract type 'Gamemode'
   gameHandler.selectGamemode(mode);
                                  ^
In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:1:0:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:27:32: error: cannot declare parameter 'mode' to be of abstract type 'Gamemode'
   void selectGamemode(Gamemode mode);
                                ^~~~
In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:6:0,
                 from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:1:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:12:7: note:   because the following virtual functions are pure within 'Gamemode':
 class Gamemode {
       ^~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:23:16: note: 	virtual void Gamemode::handleGameModeLogic()
   virtual void handleGameModeLogic()=0;
                ^~~~~~~~~~~~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:24:16: note: 	virtual void Gamemode::onTargetHitHandler(Target&)
   virtual void onTargetHitHandler(Target &target)=0;
                ^~~~~~~~~~~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\Gamemode.h:25:16: note: 	virtual void Gamemode::prepareTargetHandler(Target&)
   virtual void prepareTargetHandler(Target &target)=0;
                ^~~~~~~~~~~~~~~~~~~~
In file included from C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:1:0:
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.h:18:12: error: cannot declare field 'GameHandler::_gamemode' to be of abstract type 'Gamemode'
   Gamemode _gamemode;
            ^~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:24:43: error: cannot declare parameter 'mode' to be of abstract type 'Gamemode'
 void GameHandler::selectGamemode(Gamemode mode) {
                                           ^~~~

exit status 1

Compilation error: cannot declare parameter 'mode' to be of abstract type 'Gamemode'

Does this have to do with the fact the I don't have a gamemode.cpp file with the definitions?

sketch_jan18a.zip (4.8 KB)

Hard time with zip files on my iPhone too :wink:

Shouldn’t you pass references or pointers to the instance to your functions rather than by copy?

A pure virtual class indeed is abstract so can’t be instantiated.

Lota of errors from GameHandler.h but you haven't posted it.

Per @J-M-L, you can't have an instance of an abstract class.

I've made the necessary changes to pass it in as a pointer.

Heres the gamehandler.h

#ifndef GAMEHANDLER_H
#define GAMEHANDLER_H
#include <stdlib.h>
#include <Arduino.h>
#include "Target.h"
#include "Gamemode.h"
#include "SoloTimeMode.h"


class GameHandler {
private:
  bool _isPaused;
  bool _gameEnded;



  unsigned long _gameTimer;
  Gamemode* _gamemode;
  int _numTargets;
  Target* _targets;
  unsigned long _gameDuration;


public:
  GameHandler(Target targets[], int numTargets);
  void init();
  void selectGamemode(Gamemode &mode);
  void gameLoop();

  void handleTargetsLogic();
};


#endif

heres the gamehandler.cpp:

#include "GameHandler.h"
#include <stdlib.h>
#include <Arduino.h>


GameHandler::GameHandler(Target targets[], int numTargets) {
  _targets = targets;
  _numTargets = numTargets;
  _isPaused = true;
  _gameEnded = false;
  // _gamemode = 0;



  _gameTimer = 0;
}

void GameHandler::init() {
  for (int i = 0; i < _numTargets; i++) {
    _targets[i].init();
  }
}

void GameHandler::selectGamemode(Gamemode &mode) {
  _gamemode = mode;
  _isPaused = false;
  _gameTimer = millis();
}

void GameHandler::gameLoop() {
  if (_isPaused) {
    return;
  }

  handleTargetsLogic();
}

void GameHandler::handleTargetsLogic() {
  for (int i = 0; i < _numTargets; i++) {
    _gamemode.prepareTargetHandler(_targets[i]);
    if (_targets[i].hasBeenShot()) {
      _gamemode.onTargetHitHandler(_targets[i]);
    }
  }
}

heres the gamemode.h file

#ifndef GAMEMODE_H
#define GAMEMODE_H
#include <stdlib.h>
#include <Arduino.h>
#include "Target.h"
#include "TargetState.h"

// enum Gamemode { SOLO_TIME_CHALLENGE,
//                 SOLO_RANDOM_CHALLENGE,
//                 MULTI_RANDOM_CHALLENGE };

class Gamemode {
protected:
  unsigned long startTime;
  unsigned long endTime;

  int ledOneThreshold;
  int ledTwoThreshold;
  int ledAllThreshold;
  int ledNonThreshold;

public:
  virtual void handleGameModeLogic()=0;
  virtual void onTargetHitHandler(Target &target)=0;
  virtual void prepareTargetHandler(Target &target)=0;

};


#endif

solotimemode.h

#ifndef SOLOTIMEMODE_H
#define SOLOTIMEMODE_H
#include <stdlib.h>
#include <Arduino.h>
#include "Gamemode.h"
#include "Target.h"

class SoloTimeMode : public Gamemode {
private:
  int _score;
  int _numTargets;



public:
  SoloTimeMode(int numTargets);
  void handleGameModeLogic() override;

  void prepareTargetHandler(Target &target) override;
  void onTargetHitHandler(Target &target) override;

  void endGame();
};

#endif

and the cpp

#include <stdlib.h>
#include <Arduino.h>
#include "SoloTimeMode.h"

SoloTimeMode::SoloTimeMode(int numTargets) {
  _score = 0;
  startTime = millis();
  endTime = 0;
  _numTargets = numTargets;

  ledOneThreshold = 0;
  ledTwoThreshold = 0;
  ledAllThreshold = 0;
  ledNonThreshold = 0;
}

void SoloTimeMode::handleGameModeLogic() {
}

void SoloTimeMode::prepareTargetHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      target.setState(LED_ONE);
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      break;
    case LED_ALL:
      break;
  }
}
void SoloTimeMode::onTargetHitHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      // do nothing
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      // _score++;
      target.setState(LED_TWO);
      _score++;
      if (_score == _numTargets) { endGame(); }
      break;
    case LED_ALL:
      break;
  }
}

void SoloTimeMode::endGame() {
  endTime = millis();
}

Now this is the error im getting.

C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp: In member function 'void GameHandler::selectGamemode(Gamemode&)':
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:25:15: error: cannot convert 'Gamemode' to 'Gamemode*' in assignment
   _gamemode = mode;
               ^~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp: In member function 'void GameHandler::handleTargetsLogic()':
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:40:15: error: request for member 'prepareTargetHandler' in '((GameHandler*)this)->GameHandler::_gamemode', which is of pointer type 'Gamemode*' (maybe you meant to use '->' ?)
     _gamemode.prepareTargetHandler(_targets[i]);
               ^~~~~~~~~~~~~~~~~~~~
C:\Users\LENOVO\Documents\Arduino\sketch_jan18a\GameHandler.cpp:42:17: error: request for member 'onTargetHitHandler' in '((GameHandler*)this)->GameHandler::_gamemode', which is of pointer type 'Gamemode*' (maybe you meant to use '->' ?)
       _gamemode.onTargetHitHandler(_targets[i]);
                 ^~~~~~~~~~~~~~~~~~

exit status 1

Compilation error: cannot convert 'Gamemode' to 'Gamemode*' in assignment

Heres the main arduino code:

#include "Target.h"
#include "GameHandler.h"
#include "SoloTimeMode.h"


const int LED_PIN_1 = 7;
const int LED_PIN_2 = 6;
const uint8_t PIEZO_PIN_1 = A5;

const int LED_PIN_1a = 4;
const int LED_PIN_2a = 5;
const uint8_t PIEZO_PIN_2 = A0;


int counter = 0;

int targetSensitivity = 1000;



const int NUM_TARGETS = 2;
Target targets[NUM_TARGETS] = { Target(PIEZO_PIN_1, LED_PIN_1, LED_PIN_2),
                                Target(PIEZO_PIN_2, LED_PIN_1a, LED_PIN_2a) };

GameHandler gameHandler(targets, NUM_TARGETS);
SoloTimeMode mode(NUM_TARGETS);

void setup() {
  gameHandler.init();
  Serial.begin(9600);
  
  gameHandler.selectGamemode(mode);
}

void loop() {
  gameHandler.gameLoop();

  Serial.println(targets[0].getState());
}

I feel like im getting closer but still not there yet. I'm not sure what these errors mean.

I'll attach the files unzipped if that helps.
GameHandler.cpp (854 Bytes)
GameHandler.h (551 Bytes)
Gamemode.h (624 Bytes)
sketch_jan18a.ino (739 Bytes)
SoloTimeMode.cpp (1.0 KB)
SoloTimeMode.h (455 Bytes)
Target.cpp (1.5 KB)
Target.h (623 Bytes)
TargetState.h (236 Bytes)

@zayedalzaabi, please you Code Tags for the code of your last post. It's unreadable as is.

Yeah, Just made the changes.

The compiler is telling you why it's unhappy:

This:

      _gamemode.onTargetHitHandler(_targets[i]);

But you made _gamemode a pointer:

  Gamemode* _gamemode;

So your notation is wrong. It should probably be:

       _gamemode->onTargetHitHandler(_targets[i]);

But, I think it was a mistake to use a pointer. A Reference would be better.

I changed it back to a reference now and it compiles fine however the mian functionality isnt working correctly. Target isnt changing state based on the gamemode. It's stuck at the initial state...

Gamehandler.cpp

#include "GameHandler.h"
#include <stdlib.h>
#include <Arduino.h>


GameHandler::GameHandler(Target targets[], int numTargets, Gamemode& mode) {
  _targets = targets;
  _numTargets = numTargets;
  _isPaused = true;
  _gameEnded = false;
  _gamemode = mode;



  _gameTimer = 0;
}

void GameHandler::init() {
  for (int i = 0; i < _numTargets; i++) {
    _targets[i].init();
  }
}

void GameHandler::selectGamemode(Gamemode &mode) {
  _gamemode = mode;
  _isPaused = false;
  _gameTimer = millis();
    Serial.begin(9600);
}

void GameHandler::gameLoop() {
  if (_isPaused) {
    return;
  }

  handleTargetsLogic();
}

void GameHandler::handleTargetsLogic() {
  for (int i = 0; i < _numTargets; i++) {
    _gamemode.prepareTargetHandler(_targets[i]);
    if (_targets[i].hasBeenShot()) {
      _gamemode.onTargetHitHandler(_targets[i]);
    }
  }
}

Solotimemode.cpp

#include <stdlib.h>
#include <Arduino.h>
#include "SoloTimeMode.h"

SoloTimeMode::SoloTimeMode(int numTargets) {
  _score = 0;
  startTime = millis();
  endTime = 0;
  _numTargets = numTargets;

  ledOneThreshold = 0;
  ledTwoThreshold = 0;
  ledAllThreshold = 0;
  ledNonThreshold = 0;
}

void SoloTimeMode::handleGameModeLogic() {
}

void SoloTimeMode::prepareTargetHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      target.setState(LED_ONE);
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      break;
    case LED_ALL:
      break;
  }
}
void SoloTimeMode::onTargetHitHandler(Target &target) {
  switch (target.getState()) {
    case LED_NON:
      // do nothing
      break;
    case LED_TWO:
      break;
    case LED_ONE:
      // _score++;
      target.setState(LED_TWO);
      _score++;
      if (_score == _numTargets) { endGame(); }
      break;
    case LED_ALL:
      break;
  }
}

void SoloTimeMode::endGame() {
  endTime = millis();
} 

This means that the derived method prepareTarget() isn't really working on the gamehandler loop.
GameHandler.cpp (895 Bytes)
GameHandler.h (567 Bytes)
Gamemode.h (624 Bytes)
sketch_jan18a.ino (748 Bytes)
SoloTimeMode.cpp (1.0 KB)
SoloTimeMode.h (455 Bytes)
Target.cpp (1.5 KB)
Target.h (623 Bytes)
TargetState.h (236 Bytes)

To be exact, this function is supposed to change the state from LED_NON TO LED_ONE (since the starting state of the target is always LED_NON

 
void SoloTimeMode::handleGameModeLogic() {
 
}
 
 
void SoloTimeMode::prepareTargetHandler(Target &target) {
 
  switch (target.getState()) {
 
    case LED_NON:
 
      target.setState(LED_ONE);
 
      break;
 
    case LED_TWO:
 
      break;
 
    case LED_ONE:
 
      break;
 
    case LED_ALL:
 
      break;
 
  }
 
}

And this is the method in gamehandler. Cpp that's supposed to execute the prepareTarget method for each target.

 
void GameHandler::handleTargetsLogic() {
 
  for (int i = 0; i < _numTargets; i++) {
 
    _gamemode.prepareTargetHandler(_targets[i]);
 
    if (_targets[i].hasBeenShot()) {
 
      _gamemode.onTargetHitHandler(_targets[i]);
 
    }
 
  }
 
}

Bump

Why do you using classes, if don't understand them? Or why you don't learn the classes, if you try to use it? :slight_smile:

I helped you to manage your files previous time, but you did it again...
Make the code in one or two modules, if you have a troubles with composite the program from multiple source files.

It's not that i have an issue with classes. I have an issue with c++ since i've never any experience with it at all and i'm trying to learn as I work on the project. Used to work on java and c# for a long time before and it was certainly simpler than this.

I'm working with classes to make sure (in this case) I have the ability to create "Gamemodes" easily i nthe future without messing up or cluttering the code way too much.

Will passing it in as a const in the parameter make a difference?

No.

Could you draw the exact hierarchy of classes you have in mind?

C++ is not Java, not everything needs to be a class. For example it seems to me that the gamehandler class is really your main code and could be your .ino