Undefined reference to 'vtable for xxx'

121,949

Solution 1

The first set of errors, for the missing vtable, are caused because you do not implement takeaway::textualGame(); instead you implement a non-member function, textualGame(). I think that adding the missing takeaway:: will fix that.

The cause of the last error is that you're calling a virtual function, initialData(), from the constructor of gameCore. At this stage, virtual functions are dispatched according to the type currently being constructed (gameCore), not the most derived class (takeaway). This particular function is pure virtual, and so calling it here gives undefined behaviour.

Two possible solutions:

  • Move the initialisation code for gameCore out of the constructor and into a separate initialisation function, which must be called after the object is fully constructed; or
  • Separate gameCore into two classes: an abstract interface to be implemented by takeaway, and a concrete class containing the state. Construct takeaway first, and then pass it (via a reference to the interface class) to the constructor of the concrete class.

I would recommend the second, as it is a move towards smaller classes and looser coupling, and it will be harder to use the classes incorrectly. The first is more error-prone, as there is no way be sure that the initialisation function is called correctly.

One final point: the destructor of a base class should usually either be virtual (to allow polymorphic deletion) or protected (to prevent invalid polymorphic deletion).

Solution 2

One or more of your .cpp files is not being linked in, or some non-inline functions in some class are not defined. In particular, takeaway::textualGame()'s implementation can't be found. Note that you've defined a textualGame() at toplevel, but this is distinct from a takeaway::textualGame() implementation - probably you just forgot the takeaway:: there.

What the error means is that the linker can't find the "vtable" for a class - every class with virtual functions has a "vtable" data structure associated with it. In GCC, this vtable is generated in the same .cpp file as the first listed non-inline member of the class; if there's no non-inline members, it will be generated wherever you instantiate the class, I believe. So you're probably failing to link the .cpp file with that first-listed non-inline member, or never defining that member in the first place.

Solution 3

If a class defines virtual methods outside that class, then g++ generates the vtable only in the object file that contains the outside-of-class definition of the virtual method that was declared first:

//test.h
struct str
{
   virtual void f();
   virtual void g();
};

//test1.cpp
#include "test.h"
void str::f(){}

//test2.cpp
#include "test.h"
void str::g(){}

The vtable will be in test1.o, but not in test2.o

This is an optimisation g++ implements to avoid having to compile in-class-defined virtual methods that would get pulled in by the vtable.

The link error you describe suggests that the definition of a virtual method (str::f in the example above) is missing in your project.

Solution 4

You may take a look at this answer to an identical question (as I understand): https://stackoverflow.com/a/1478553 The link posted there explains the problem.

For quick solving your problem you should try to code something like this:

ImplementingClass::virtualFunctionToImplement(){...} It helped me a lot.

Solution 5

Missing implementation of a function in class

The reason I faced this issue was because I had deleted the function's implementation from the cpp file, but forgotten to delete the declaration from the .h file.

My answer doesn't specifically answer your question, but lets people who come to this thread looking for answer know that this can also one cause.

Share:
121,949
TacticalMin
Author by

TacticalMin

Updated on January 28, 2022

Comments

  • TacticalMin
    TacticalMin over 2 years
    takeaway.o: In function `takeaway':
    project:145: undefined reference to `vtable for takeaway'
    project:145: undefined reference to `vtable for takeaway'
    takeaway.o: In function `~takeaway':
    project:151: undefined reference to `vtable for takeaway'
    project:151: undefined reference to `vtable for takeaway'
    takeaway.o: In function `gameCore':
    project.h:109: undefined reference to `gameCore<int>::initialData(int)'
    collect2: ld returned 1 exit status
    make: *** [takeaway] Error 1
    

    I keep getting this Error from the linker , i know it has something to do with inline functions getting a vtable temporarily stored. But what that entails i am not quite sure. I would assume it has something to do with how i call gameCore's constructor in the initilization list of takeaway.cpp

    I have a templated class (gameCore.h) and a class (takeaway.cpp) that is inheriting from gameCore The vtable error is called 3 times 1)in takeaways constructor 2) takeaways destructor 3)in gameCores constructor

    I am using G++ Here is the code: (i know it may seem hard to read but i have marked off exatcly where the erros occur) takeaway.h

    #ifndef _TAKEAWAY_H_
    #define _TAKEAWAY_H_
    #include<map>
    #include<cctype>
    #include<stack>
    #include<map>
    #include<iostream>
    #include<string>
    #include<cstdlib>
    #include"gameCore.h"
    #include<vector>
    using namespace std;
    class takeaway : public gameCore<int>
    {
     private:
    
     public:
    // template<class Penny>
     void  textualGame();
     bool isNum(string str);
    // template<class Penny>
     stack<int> initialData(int initial);
    // template<class Position>
     int score (int position);
    // template<class Position>
     stack<int> addStack(int currentPos, stack<int> possiblePositions);
    // template<class Penny>
     takeaway (int initial);
    // template<class Position>
     ~takeaway();
    };
    bool isNum(string str);
    int charToint(char *theChar);
    #endif
    

    takeaway.cpp

    /*
    Description :
        This game communicates with the gameCore class to determine the results
        of a game of takeaway played between two computers or a computer and human.   
    */
    
    #include "takeaway.h"
    
     /*
     Description:Creates a stack represening initial data
     Note:Change to a vector eventually
     return : stack of int
     */
     stack<int> takeaway:: initialData(int initial){
       stack<int> returnStack;
       int theScore = score(initial);
       int final;
       if(initial ==0)
       {
        final = 1;
       }
       else
       {
        final = 0;
       }
       returnStack.push(theScore);
       returnStack.push(final);
       return returnStack;
     }
    
    
     /*
     Description: a textual representation of the game
     Note: This is still terribly wrong
     */
    
     void textualGame(){
      cout <<"this is the best i could do for a graphical representation";
    
     }
     /*
     Description: Deetermines if a number is even
     Note: Helper function for determining win or loss positions
     Returns: 1 if it is and 0 if it is not
     */
     int takeaway::score(int position){
      if(position % 2 == 0)
      {
         return 1;
      }
      return 0;
     }
     /*
       Description: Will return a stack , withouth the given postion in it
       will contain all positions possible after the given position
       along with anyother that wehre in the given stack.This function
       Must also update the map to represent updated positions
       Takes: a position to check and a stack to return
       Returns: A stack of possible positions.
    
     */
     stack<int>  takeaway::addStack(int currentPos, stack<int> possiblePositions ){
      if(currentPos != 0)
      {
        // If even
        if( currentPos % 2 == 0)
        { 
           // Create a data aray with score of the new positon and mark it as not final
        int data[] = {score(currentPos/2),0};
        vector<int> theData(data, data+sizeof(data));
            int pos = currentPos/2;
           // Add it to the map
           //this -> gamesMap[currentPos/2] = dataArray; 
           this -> gamesMap.insert(std::pair<int, vector<int> >(pos, theData));
           // Add it to the possible positions
           possiblePositions.push(pos);
        }
        if(currentPos % 3 == 0)
        {
    
        int data[] = {score(currentPos/3),0};
           vector<int> theData(data,data+sizeof(data));
           int  pos = currentPos/3;
           //this -> gamesMap[currentPos/3] = dataArray; 
           this -> gamesMap.insert(std::pair<int, vector<int> >(pos, theData));
           possiblePositions.push(pos);
        }
        // Work for the position that represents taking one penny
        int minusFinal = 0;
        if(currentPos - 1 == 0)
        {
          minusFinal = 1;
        }
        int data[] = {score(currentPos - 1),minusFinal};
        vector<int> theData(data,data+sizeof(data));
        int pos  = currentPos - 1;
       // this -> gamesMap[currentPos -1] = dataArary
        this->gamesMap.insert(std::pair<int,vector<int> >(pos, theData));
        possiblePositions.push(pos);
      }
      return possiblePositions;
    
     }
     /*
     Description: Constructor for the takeaway game
    OA takes: a initial position, and initial data for it
    
     */
     takeaway::takeaway(int initial):gameCore<int>::gameCore(initial){ //<--- ERROR HERE
     //Constructor
     }
     /*
     Description: Destuctor
     */
     takeaway::~takeaway(){ // <--------------------- ERROR HERE
     //Destructor
     }
    
    
    //checks input and creates game.
    int main(int argc, char* argv[]){
      int numberPennies ;
      string game = argv[0];
      if(argc == 2 && isNum(argv[1]) )
      {
        int pennies = charToint(argv[1]);
         takeaway gameInstance(pennies ); // Creates a instance of $
      }
     //  else if(argc == 3 && argv[1] == "play" && isNum(argv[2]) )
     // {
     //   int pennies = charToint(argv[2]);
     //   takeaway<int> gameInstance(pennies); // Craete a human playab$
     // }
      else
      {
        cerr << "Error->Usage: " << game <<" [play] numberOfPennies \n";
        exit (1);
      }
     return 0;
     }
    
    //Converts a char to a integer
    int charToint(char *theChar){
      int theInt = atoi(theChar);
      return theInt;
    }
     //Determines if a string is numeric
    bool isNum(string str){ 
      for(int i = 0;i < str.length() ;i++){
       if(isdigit(str[i]) != 1)
       {
         cerr << "Error->Input: Number must be a Positive Integer the charecter '" << str[i]<< "' invalidated your input. \n" ;
         exit(1);
         return false;
       }
      }
      return true;
    }
    

    gameCore.h

    /*
    gameCore.h
    
    Description:
        This class created gameMap that are written as a template
        They will communicate with the specific game and the algorithm
        To keep track of positions ans there values.
    */
    #ifndef GAMECORE_H
    #define GAMECORE_H
    #include <map>
    #include <stack>
    #include <string>
    #include <vector>
    using namespace std;
    
    
    template <class Position>
    class gameCore
    {
     protected:
        //Best Move used by algorithim
        Position bestMove;
        //The current highest score used by the algorithim
        int highestScore ;
        //Stack to be used to remmeber what move created the score
        stack<Position> movedFrom;
        //Stack used for the algorithim.
        stack<Position> curWorkingPos;
        //The actual Map that the data will be held in.
        map<Position,vector<int> > gamesMap;
     public:
    
        /*
        Description : finds the data array for a poisition
        takes: a Position
        Returns: a array of integers /**
        */
        virtual stack<int> initialData(Position pos) = 0;
            /*
        Description: Game must implement a way to determine a positions
        score.
    
        */
            virtual int score(Position pos) = 0;
            /*
        Description: A Graphical representation of the game
    
        */
        virtual void textualGame() = 0;
    
        /*
        Description: a virtual function implemented by the child class
        it will return a stack without the given position in it.This stack
        will contain all positions available from the given postion as well as 
        all position already in the given stack. Also it will update the map with
        all generated positions.
        TAkes: a postion to check and a stack of currently working positons.
    
        */
        virtual stack<Position> addStack(Position currentPos, stack<Position> possiblePositions ) = 0;
        /*
           Description:Constructor that
           Creates a Map with positions as the key.
           And an array of two integers that represent the positions
           value and if we have moved here in the past.
           Takes: a Initial Position and a Array of integers
        */
        gameCore(Position initial){              // <-----ERROR HERE
           //Determine the initial data and add it to the map and queue.
           stack<int> theData = initialData(initial);
           int first = theData.top();
               theData.pop();
               int second = theData.top();
           theData.pop();
           int initialData[] = {first,second};
               vector<int> posData(initialData,initialData+sizeof(initialData));
           gamesMap[initial] = posData;
           curWorkingPos.push(initial);
        }
        /*
        Description:
           A destructor for the class
        */
         ~gameCore(){
            //I do nothing but , this class needs a destructor
    
        }
        /*
           Description: Takes the current position and returns 
           that positions Score.
           Takes: A position 
           Returns:A integer that is a positions score.
    
        */
        int getPosScore(Position thePos) const {
            return this ->gamesMap.find(thePos)->second[0];
        }
        /*
        Description: Adds values to a stack based on the current position
        Takes: a poistion
        */
        void updateStack(Position curPos){
            this ->curWorkingPos =addStack(curPos,this ->curWorkingPos ); // get a stack from the game
            // The game has a function that takes a position and a stack and based on the positions returns a stack identical to the last but with added values that represent valid moves from the postion./
        }
        /*
           Description : Takes a positions and returns a integer
           that depends on if the position is a final pos or not
           Takes: A position
           Returns: A Bool that represents if the position is a final(1)  or not (0).
    
        */
            // Possible change
        bool isFinal(Position thePos) {     
            typename map<Position,vector<int> >::iterator iter =  this ->gamesMap.find(thePos);
            return iter->second[1] == 1 ;
        }
        /*
        Description: Based on the given position determine if a move needs to be made.
        (if not this is a end game position and it will return itself) If a move needs
        to be made it will return the position to move to that is ideal.
        Note: (because all positions can be represented as integers for any game , the return
        type is a integer)
    
        */
        int evaluatePosition(Position possiblePosition ){
               if(isFinal(possiblePosition)) //If this is a final position
            {
               return  getPosScore(possiblePosition);  //Return the score 
            }
               else
               {
             updateStack(possiblePosition); //Put all possible positions from this in thte stack
             while(this -> curWorkingPos.size() != 0)
             {
               this -> movedFrom.push(this->curWorkingPos.front()); //take the top of the possible positions stack and set it the the moved from stack
               this -> curWorkingPos.pop();
               int curScore =  evaluatePosition(this ->movedFrom.top());  //Recursive call for school
               curScore = curScore * -1; //Negate the score
               if(curScore > this -> highestScore) // if the score resulting from this position is biggest seen
               {
                 highestScore = curScore;
                 this ->movedFrom.pop();  //do this first to get rid of the the lowest point
                 this -> bestMove = this ->movedFrom.top();  // mark where the lowest point came from
               }
              else
               {
                 this -> movedFrom.pop(); 
               }
             }
               }
            return this -> bestMove;
        }
        //A Structure to determine if a position has a lower value than the second
        struct posCompare{
            bool operator() (Position pos1,Position pos2) const {
                return (pos1.getPosScore() < pos2.getPosScore());
                }
            };
    };
    #endif
    
  • bdonlan
    bdonlan over 12 years
    This is indeed a problem, but not the cause of the OP's error
  • Mike Seymour
    Mike Seymour over 12 years
    @bdonlan: it is the cause of the last error, caused by an attempt to call gameCore::initialData() which has no implementation.
  • bdonlan
    bdonlan over 12 years
    nope - this is a link-time error. It knows nothing about runtime initialization ordering. If such an error was to occur, it would happen either at compile time or runtime.
  • Mike Seymour
    Mike Seymour over 12 years
    @bdonlan: the compiler generates a call to gameCore::initialData(), since that is the active override during the constructor of gameCore. It does not know whether that function is implemented or not, so it can't generate an error at that stage. The linker discovers that the function is not implemented, and generates the error we see.
  • bdonlan
    bdonlan over 12 years
    Ah I see what you mean - it's a pure virtual function, so there's (usually) no implementation. The compiler generates a direct call to the pure virtual function's implementation (which usually doesn't exist), and so the linker errors out. The compiler can't error out, though, because technically you can have an implementation for the pure virtual in another translation unit...
  • sage
    sage about 7 years
    One reason a cpp file would not be linked is because one forgot to add it to the build. In my case, editing the implementation uncovered that the object did not get rebuilt before linking commenced! (I had double- and triple-checked that cpp file's contents before noticing it wasn't getting compiled or linked)