未定义的引用“为xxx的vtable”
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的构造函数有什么关系
我有一个模板类(gameCore.h)和一个类(takeaway.cpp)是从gameCoreinheritancevtable错误被称为3次1)在takeaways构造函数2)takeaways析构函数3)在gameCores构造函数
我正在使用G ++这里是代码:(我知道它可能看起来很难阅读,但我已经标出关于erros发生的地方)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
对于缺less的vtable,第一组错误是因为你没有实现takeaway::textualGame()
; 而是实现一个非成员函数textualGame()
。 我认为添加缺less的takeaway::
将解决这个问题。
最后一个错误的原因是您正在从gameCore
的构造函数调用虚函数initialData()
。 在这个阶段,根据当前正在构build的types( gameCore
) 而不是最派生类( takeaway
)来调度虚函数。 这个特定的函数是纯虚拟的,所以在这里调用它会导致不确定的行为。
两种可能的解决方
- 将
gameCore
的初始化代码移出构造函数,并移入一个单独的初始化函数,该函数必须在对象完全构build后调用; 要么 - 将
gameCore
分成两个类:一个抽象接口由takeaway
实现,一个包含状态的具体类。 首先构造takeaway
,然后将其传递给具体类的构造函数(通过对接口类的引用)。
我会推荐第二个,因为这是向更小的class级和更宽松的耦合的方向发展,错误地使用class级会更困难。 第一个更容易出错,因为没有办法确保初始化函数被正确调用。
最后一点:基类的析构函数通常应该是虚拟的(允许多态删除)或保护(以防止无效的多态删除)。
一个或多个.cpp文件没有被链接,或者某些类中的一些非内联函数没有被定义。 特别是takeaway::textualGame()
的实现无法find。 请注意,您已经定义了一个textualGame()
,但是这不同于takeaway::textualGame()
实现 – 可能您只是忘记了takeaway::
。
错误意味着链接器无法find类的“vtable” – 每个具有虚函数的类都有一个与之关联的“vtable”数据结构。 在GCC中,这个vtable与第一个列出的非内联成员在同一个.cpp文件中生成。 如果没有非内联成员,我相信在实例化该类的任何地方都会生成。 所以你可能无法将.cpp文件与首先列出的非内联成员链接起来,或者从不首先定义该成员。
如果一个类定义了该类之外的虚拟方法,那么g ++只在包含首先声明的虚方法的类外定义的目标文件中生成该vtable:
//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(){}
vtable将在test1.o中,但不在test2.o中
这是g ++实现的一种优化,以避免编译类内定义的虚拟方法,这些虚方法会被vtable拉入。
您所描述的链接错误表明,在您的项目中缺less虚拟方法(上例中为str :: f)的定义。
你可以看看这个答案相同的问题(据我所知): https : //stackoverflow.com/a/1478553张贴在那里的链接解释了这个问题。
为了快速解决你的问题,你应该尝试编写这样的代码:
ImplementingClass::virtualFunctionToImplement(){...}
它帮了我很多。
它暗示你未能链接显式实例化的基类public GameCore(而头文件转发声明它)。
由于我们对构buildconfiguration/库依赖关系一无所知,所以我们无法确切知道哪些链接标记/源文件丢失了,但我希望这个提示能够帮助您解决问题。
在类中没有实现一个函数
我遇到这个问题的原因是因为我已经从cpp文件中删除了函数的实现,但忘记了从.h文件中删除声明。
我的答案没有具体回答你的问题,但让来自这个线程寻找答案的人知道,这也可以是一个原因。