Hi

So I've been developing this game for a game design class for most of the semester. While I'm not new to C++ and Object Oriented Design, the theory of it is often a lot easier to comprehend and know than the actual application of it. Needless to say, I've run numerous problems throughout the development of my game, most being surmountable.

However, my next goal is to get the code leak free via valgrind on Linux. Unfortunately, I've been developing on windows using Dev-Cpp and the Mingw compiler, and this has spawned some problems. While my code compiles and runs on Windows, when I compile using G++ on Linux, I'm getting the dreaded...

undefined reference to `vtable for class'
undefined reference to `typeinfo for class'

I've done research into what the problem might be, I've visited the GCC FAQ entry about it, I've read accounts on this board. I've encountered this before, and it came from failing to implement a purely virtual function in some manner (Stub or full implementation) in a derived class. I've read over the code of the classes the error involves, and this does not seem to be the case. I've also been told that this error can come up when "the destructor is not adequately defined," but that not a concrete enough explanation as to what's going on for me.

To try to circumvent this problem, I tried making every function of the base class that was virtual pure-virtual, as to force a definition for each function in each derived class, stub or fully implemented, also in hopes of forcing the vtable for each class into its object file, but much to no avail. So at my wits end, I've come to this forum hopefully to find some answers. Are there any other things that such an error can result from? Or any advice or pointers that can be given?

Let me know if I should post my code, as I'm hesitant to because it will be four classes (Base, Derived, More Derived), a lot of code, and I'm not sure if I should omit comments/functions definitions/or what.

Thanks in advanced,
Yates Monteith

Recommended Answers

All 6 Replies

Yes, this case I would post the code. I figure that (a) you have actually googled this. (b) and tried some testing.
(c) your using a compiler that give better error messages that VC++.

However, this is not a completely uncommon error so I would like to explain what it normally means and if that doesn't fix it then please put some code up.

the destructor not adequately defined, normally means that you have a pointer that you cannot find the vtable back to the base.
E.g. consider class Base; class A : public Base; class B : public A;
No in a separate file you define stuff that uses ptrs/ref or B, and those ptrs get deleted OR those refs get moved out of scope. You don't have sufficient includes in the file, but you have pre-definitions. Then you have an implicit/direct call to a destructor that needs to call A and Base destructor. gcc can't resolve that.

So I AM GUESSING!!! that the error is in the lack of an include.

However, some code is going to help here so I think some posting is in order. If you have large methods maybe strip them down.

Hi!

Thanks for the reply. After reading your post and looking through my code, I think that could possibly be the problem. In my more-derived class, I do have a reference to another class which could be calling the reference out of scope. I guess I'll start off with a description of the hierarchy in question, then post the code with some functions truncated.

My basest class is Drawable. It represents objects which have (Read: Private Variables) an x,y coordinate and a x,y velocity. It has a set of non-virtual accessor/mutator functions for speed/coordinates/etc, and a set of pure-virtual functions. I mentioned why these functions are pure virtual in the second post.

/* Drawable Class Header */

/* Preprocessor Directives */
#ifndef DRAWABLE__H
#define DRAWABLE__H

/* Necessary Libraries */
#include <SDL/SDL.h>
#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include "frame.h"
#include "drawable.h"

/* Global Constants*/
const float BACKGROUND_SPEED = 50.0;
const float PLAYER_SPEED = 5.0;
const int WIDTH = 670;
const int HEIGHT = 303;
const float COLLISION_DISTANCE = 35;
const float MAX_DISTANCE = 250;
const int EXPLOSION_SPEED = 30;
const float DUCK_XSPEED = 30;

class Drawable {
   public:
      Drawable(float x, float y, float xs, float ys) :
         xCoordinate(x), yCoordinate(y), xSpeed(xs), ySpeed(ys) { }

      Drawable(const Drawable& s) :
         xCoordinate(s.xCoordinate), yCoordinate(s.yCoordinate),
         xSpeed(s.xSpeed), ySpeed(s.ySpeed) { }

      virtual ~Drawable() {}

/* Pure Virtual Functions */
      virtual void draw() = 0;
      virtual void update(Uint32 ticks) = 0;
      virtual void advanceFramesUp() = 0;
      virtual void advanceFramesDown() = 0;
      virtual void resetFrames() = 0; 
      virtual void setFrames(std::vector<Frame> *) = 0;
      virtual void shoot() = 0;
      virtual bool shooting() const = 0;
      virtual bool collision(float, float) const = 0;
      virtual bool isExploding() const = 0;
      virtual void cullBullets() = 0;

/* Non Virtual Functions */
      float getX() const { return xCoordinate; }
      float getY() const { return yCoordinate; }
      void setX(float x) { xCoordinate = x; }
      void setY(float y) { yCoordinate = y; }
      float getSpeedX() const { return xSpeed; }
      float getSpeedY() const { return ySpeed; }
      void setSpeedY(float s) { ySpeed = s; }
      void setSpeedX(float s) { xSpeed = s; }
      void incrSpeedX(float incr) { xSpeed += incr; }
      void incrSpeedY(float incr) { ySpeed += incr; }
      void decrSpeedX(float incr) { xSpeed -= incr; }
      void decrSpeedY(float incr) { ySpeed -= incr; }
      void dragSpeedX(float incr) { xSpeed *= incr; }
      void dragSpeedY(float incr) { ySpeed *= incr; }
   protected:
      float xCoordinate;
      float yCoordinate;
      float xSpeed;
      float ySpeed;
};
#endif

Duck is a derived class of Drawable. It has a few other private variables, including a vector of type Frame (Another derived of drawable, different hierarchy), a vector of type bullet (A derived of sprite, sprite derived from Drawable), and a couple other primitive data types. It also has all the pure-virtual functions from Drawable defined. Here's the code:

#include <vector>
#include <iostream>
#include "frame.h"
#include "drawable.h"
#include "bullet.h"

using std::vector;

class Duck : public Drawable 
{
   public:
      //Default Constructor
      Duck(float x, float y, float xs, float ys, Frame *f, int i)
          : Drawable(x, y, xs, ys), currentFrame(0), bulletFrame(f), shootDirection(i){ 
      //Destructor
      ~Duck() { }
      
/* Inline Functions */
      //getFrame function.  Returns member variable Frame frame         
      Frame* getFrame() const { return new Frame((*duckFrames)[currentFrame % duckFrames->size()]); }
      //setFrames function.  Sets duckFrames to passed frame vector pointer
      void setFrames(std::vector<Frame> *f) { duckFrames = f; }
      //getCurrentFrame function.  Returns the index of the current frame
      int getCurrentFrame() const { return currentFrame % duckFrames->size(); }   
      //isExploding: Returns false, Duck objects cannot be exploding and ducks
      bool isExploding() const { return false; }
      //shooting function.  Returns true if bullets vector is non-empty
      bool shooting() const { return bullets.size() > 0; }//(bullets.size() > 0); }
      //resetFrames function.  Resets currentFrame to 0
      void resetFrames() { currentFrame = 0; }
      /* Stub Defined Virtual Functions */
      void advanceFramesUp() {}
      void advanceFramesDown() {}

/* Implementation Defined Functions */
      //Shooting and collision functions
      void cullBullets();
      void shoot();
      float distance(float x1, float y1, float x2, float y2) const; 
      bool collision(float x, float y) const;

      //Drawing Functions
      void advanceFrame(Uint32 ticks);
      void update(Uint32 ticks);
      void draw();
      
   private:
      //Vector for duck frames of animation
      std::vector<Frame> *duckFrames;
      //Vector for current Frame of animation
      int currentFrame;
      //Frame pointer for bullet image
      Frame *bulletFrame;
      //Vector of bullets
      vector<Bullet> bullets;
      int shootDirection;
};

//IMPLEMENTATION OF DUCK.H

#include "duck.h"

//Draw Function:
//Draws player to screen, draws players active bullets
void Duck::draw()
{ 
}

void Duck::advanceFrame(Uint32 ticks) 
{
}

//Update function
//updates the duck's location along with the location of all active duck-bullets
void Duck::update(Uint32 ticks) 
{
}

//cullBullets function
//Erases bullets that have traveled too far
void Duck::cullBullets() 
{
}

//Shoot function
//Creates new bullets in the player::std::<Bullet>Vector
void Duck::shoot() 
{
}

//Collision function
//Checks for collisions between duck-bullets and a set of x,y coordinates
bool Duck::collision(float x, float y) const 
{  
}

//Distance function
//Finds the hypot distance between two sets of points
float Duck::distance(float x1, float y1, float x2, float y2) const 
{
}

Finally, SmartDuck is a derived class of Duck. It only overloads the Update and Draw functions, inheriting everything else, as is. It has a reference to another class (Player, so it can get data access), along with an enumerator, and another primitive in its private section. There are a couple things commented out in the header, those are purely for debugging purposes.

#include <iostream>
#include "duck.h"
#include "player.h"

class SmartDuck : public Duck 
{
   public:
      SmartDuck(float x, float y, float xs, float ys, Frame *f, Drawable &p, /* SDL_Surface *screen ,*/ int i)
      : Duck(x, y, xs, ys, f, i), /*io(IOSingleton::getInstance(screen))*/ player(p), currentMode(NORMAL), initSpeedX(xs) { }

      void draw();
      void update(Uint32 ticks);
      enum MODE {NORMAL, TRAIL, PANIC};
       
   private:	
      //IOSingleton *io;
      Drawable & player;
      MODE currentMode;
      float initSpeedX;
};

//IMPLEMENTATION FOR SMARTDUCK.H

#include <cmath>

#include "smartDuck.h"

const float SAFE_DISTANCE = WIDTH / 2;
const float MIN_DUCK_XSPEED = -300;
const float MAX_DUCK_XSPEED = -200;

float distance(int x1, int y1, int x2, int y2) 
{
}

void SmartDuck::draw() 
{
}

void SmartDuck::update(Uint32 ticks) 
{ 
}

Finally (Sorry, this is getting a little absurd), we have the Player class, immediatly derived from Drawable.

#include <vector>
#include <iostream>
#include "frame.h"
#include "drawable.h"
#include "bullet.h"

using std::vector;

class Player : public Drawable
{
   public:
      //Default constructor
      Player(float x, float y, float xs, float ys, Frame *f)
                 : Drawable(x, y, xs, ys), currentFrame(0), bulletFrame(f) {}
      
     //Destructor
      ~Player() { delete bulletFrame; }      
      
 /* Implementation defined functions */
      void draw();
      bool collision(float x, float y) const;

      float distance(float x1, float y1, float x2, float y2) const;
      void cullBullets();
      void shoot();
      void advanceFramesUp();
      void advanceFramesDown();     
      
/* Inline functions */
      //setFrames function.  Sets the vector object playerFrames to vector pointer parameter
      void setFrames(std::vector<Frame> *f) { playerFrames = f; }
      //getFrame function.  Returns the current frame object
      Frame* getFrame() const { return new Frame((*playerFrames)[currentFrame]); }
      //getCurrentFrame function.  Returns the index of the current frame
      int getCurrentFrame() const { return currentFrame; }
      //shooting function.  Returns true if there are bullets draw on the screen
      bool shooting() const { return(bullets.size() > 0); }
      //isExploding function.  Returns false, as players are not exploding
      bool isExploding() const { return false; }
      //Update function.  Updates the position of the player sprite
      void update(Uint32 ticks);
      //resetFrames function.  Resets currentFrame to 0
      void resetFrames() { currentFrame = 0; }

   private:
      std::vector<Frame> *playerFrames;
      int currentFrame;
      Frame *bulletFrame;
      vector<Bullet> bullets;
};

//IMPLEMENTATION OF PLAYER.H
#include "player.h"
//Update function
//updates the players location along with the location of all active player-bullets
void Player::update(Uint32 ticks) 
{
}

//cullBullets function
//Erases bullets that have traveled too far
void Player::cullBullets() 
{
}

//Draw Function:
//Draws player to screen, draws players active bullets
void Player::draw() 
{
}

//advanceFramesUp function, advances frames for movement in up direction
void Player::advanceFramesUp()
{  
}

//advanceFramesDown function, advances frames for movement in down direction
void Player::advanceFramesDown()
{
}

//Shoot function
//Creates new bullets in the player::std::<Bullet>Vector
void Player::shoot() 
{
}

//Distance function
//Finds the hypot distance between two sets of points
float Player::distance(float x1, float y1, float x2, float y2) const 
{
}

//Collision function
//Checks for collisions between player-bullets and duck objects
bool Player::collision(float x, float y) const 
{  
}

There errors I'm getting are:

gameManager.o: In function `Player':
/home/yates/Desktop/the abstract expirement/player.h:14: undefined reference to `vtable for Player'
gameManager.o: In function `GameManager::loadPlayer()':
/home/yates/Desktop/the abstract expirement/gameManager.cpp:302: undefined reference to `vtable for Player'
gameManager.o: In function `SmartDuck':
/home/yates/Desktop/the abstract expirement/smartDuck.h:9: undefined reference to `vtable for SmartDuck'
gameManager.o: In function `GameManager::loadDucks()':
/home/yates/Desktop/the abstract expirement/gameManager.cpp:199: undefined reference to `vtable for SmartDuck'
gameManager.o: In function `GameManager::fragDucks()':
/home/yates/Desktop/the abstract expirement/gameManager.cpp:226: undefined reference to `typeinfo for Player'

And here is the relevant code for those areas:

Nota Bene: the player object is Drawable*, the ducks object is std::vector<Duck*>

void GameManager::loadPlayer()
{
   player = new Player(50, HEIGHT / 2, 0, 0, new Frame(bulletSurface, screen, bulletSurface->w, bulletSurface->h, 0, 0));
   player->setFrames(playerFrames);
}

void GameManager::loadDucks() 
{
//Trivial code omitted
  Drawable pDuck
   pDuck = new SmartDuck(x, y, xs, ys, new Frame(missleSurface, screen, missleSurface->w, missleSurface->h, 0, 0), *player, /* screen ,*/ 1);
   pDuck->setFrames(duckFrames);
   ducks.push_back(pDuck);
   }

void GameManager::fragDucks()
{
   //Additional Code Omitted, line 225
    if (dynamic_cast<Player*>(player)->collision(duckX, duckY))
   //Additional Code omitted
}

So it seems my errors are coming from Construction and trying to cast pointer objects. The obvious thought is, why not take out the cast in fragDucks? Well, unfortunately, I've introduced a fairly long polymorphic hierarchy (There are still 4 or so classes I haven't posted, but are working fine), and if I don't do the cast, I risk referencing a null pointer, or accessing a function not defined for the class player currently represents.

So I'm sorry this got so long, but you've been very helpful so far, and I appreciate any further time you put into looking at my code. Hopefully it doesn't make your eyes bleed too badly.

Sorry I had a quick look at this. The problem is that I cant compile it since there is lots missing and you have a link-time error.

Additionally you have missed (I think) a "}" on the duck constructor.

Can you post the program as a tar.gz or however you like, but put it as an attachment. (sorry I should have said that in the first message)

Thanks for the look, perhaps I should've asked about posting it in the first place. The missing brace is most likely a typo in the code that I had to modify before posting. But anyway...

Here it is. It's in .zip form because apparently Daniweb doesn't like .tar.gz. I've made a few little adjustments to it to help size and complexity, like disabling a couple in-program debugging features, sound, etc. But a heads up, that caused a number of unused parameter/unused variable warnings, but it shouldn't really have any effect on the heart of the problem.

It's C++ / SDL, but the necessary SDL libraries are not included. They're kind of weighty, and one of them (Vanilla SDL) is OS specific. They can easily be downloaded via Dev-Cpps Packaging system, or the Synaptic Package Manager in Linux. Below are links to download them from the official SDL website, where they can be downloaded in compressed form.

SDL
http://libsdl.org/download-1.2.php

SDL_Image
http://www.libsdl.org/projects/SDL_image/

SDL_TTF
http://www.libsdl.org/projects/SDL_ttf/

SDL_Mixer
http://www.libsdl.org/projects/SDL_mixer/

Thanks again for your help,
Yates Monteith

Oh I am sorry but I have just LOL big time!!!

You forgot to compile and include smartDuck.cpp and player.cpp in you makefile.

Well in light of that I would suggest that your next project look at splitting the program into shared libraries built in sub-directories and using some Makefile builder.

For this project, just add a player.o and smartDuck.o to your makefile and remember to add it to the link line.

p.s. Debugging with the -O2 option is pretty hairy, I would drop that from your makefile [Except production release, but then you drop the -g]

Sorry to put you through the trouble of sending a whole project file.

Ugh, talk about a brain fart of massive proportions. A good learning experience though. Maybe someone should add that part to the GCC FAQ, heh.

Though could you tell me more about about Makefile builders? Is that a type of application? What are good choices?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.