未定义对 'vtable for xxx' 的引用 [英] Undefined reference to 'vtable for xxx'

查看:30
本文介绍了未定义对 'vtable for xxx' 的引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我不断从链接器收到此错误,我知道它与临时存储 vtable 的内联函数有关.但这意味着什么我不太确定.我认为这与我如何在 takeaway.cpp 的初始化列表中调用 gameCore 的构造函数有关

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

我有一个模板类 (gameCore.h)和一个继承自gameCore的类(takeaway.cpp)vtable 错误被调用 3 次1)在外卖构造函数中2) 外卖析构函数3)在gameCores构造函数中

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

我正在使用 G++这是代码:(我知道它可能看起来很难阅读,但我已经明确地标出了错误发生的位置)外卖.h

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

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 
";
    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. 
" ;
     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

推荐答案

第一组错误,对于丢失的vtable,是因为你没有实现takeaway::textualGame();相反,您实现了一个非成员函数 textualGame().我认为添加缺少的 takeaway:: 会解决这个问题.

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.

最后一个错误的原因是你从 gameCore 的构造函数中调用了一个虚函数 initialData().在这个阶段,根据当前正在构造的类型(gameCore),不是最派生的类(takeaway)来调度虚函数.这个特定的函数是纯虚函数,因此在这里调用它会产生未定义的行为.

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.

两种可能的解决方案:

  • gameCore 的初始化代码移出构造函数并放入单独的初始化函数中,该函数必须在对象完全构造后调用;或
  • gameCore分成两个类:一个由takeaway实现的抽象接口,一个包含状态的具体类.先构造takeaway,然后(通过接口类的引用)传递给具体类的构造函数.
  • 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).

这篇关于未定义对 'vtable for xxx' 的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆