C++ 未定义对 'vtable for xxx' 的引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7665190/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Undefined reference to 'vtable for xxx'
提问by TacticalMin
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
我不断从链接器收到此错误,我知道它与临时存储 vtable 的内联函数有关。但这意味着什么,我不太确定。我认为这与我如何在 takeaway.cpp 的初始化列表中调用 gameCore 的构造函数有关
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
我有一个模板类 (gameCore.h) 和一个继承自 gameCore 的类 (takeaway.cpp) vtable 错误被称为 3 次 1) 在外卖构造函数中 2) 外卖析构函数 3) 在 gameCores 构造函数中
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
我正在使用 G++ 这里是代码:(我知道它可能看起来很难阅读,但我已经准确地标记了错误发生的地方)外卖.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
外卖.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
游戏内核.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
采纳答案by Mike Seymour
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.
第一组错误,对于缺少的 vtable,是因为你没有实现takeaway::textualGame()
;相反,您实现了一个非成员函数,textualGame()
. 我认为添加缺少的内容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
), notthe most derived class (takeaway
). This particular function is pure virtual, and so calling it here gives undefined behaviour.
最后一个错误的原因是您正在initialData()
从 的构造函数调用虚函数gameCore
。在这个阶段,虚函数是根据当前正在构造的类型(gameCore
)而不是派生程度最高的类(takeaway
)来调度的。这个特殊的函数是纯虚拟的,所以在这里调用它会产生未定义的行为。
Two possible solutions:
两种可能的解决方案:
- Move the initialisation code for
gameCore
out of the constructor and into a separate initialisation function, which must be called afterthe object is fully constructed; or - Separate
gameCore
into two classes: an abstract interface to be implemented bytakeaway
, and a concrete class containing the state. Constructtakeaway
first, and then pass it (via a reference to the interface class) to the constructor of the concrete class.
- 将初始化代码
gameCore
移出构造函数,移到一个单独的初始化函数中,该函数必须在对象完全构造后调用;或者 - 分离
gameCore
成两类:的抽象接口通过实现takeaway
,以及含有该状态的具体类。takeaway
首先构造,然后将其(通过对接口类的引用)传递给具体类的构造函数。
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).
最后一点:基类的析构函数通常应该是虚拟的(允许多态删除)或受保护的(防止无效的多态删除)。
回答by bdonlan
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.
您的一个或多个 .cpp 文件未链接到,或者某些类中的某些非内联函数未定义。特别是,takeaway::textualGame()
找不到 的实现。请注意,您已经textualGame()
在顶层定义了 a ,但这与takeaway::textualGame()
实现不同 - 可能您只是忘记了takeaway::
那里。
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.
错误意味着链接器找不到类的“vtable”——每个具有虚函数的类都有一个与之关联的“vtable”数据结构。在 GCC 中,这个 vtable 是在与类的第一个列出的非内联成员相同的 .cpp 文件中生成的;如果没有非内联成员,我相信它会在您实例化类的任何地方生成。因此,您可能无法将 .cpp 文件与第一个列出的非内联成员链接,或者从不首先定义该成员。
回答by uwedolinsky
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:
如果一个类在该类之外定义了虚方法,则 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(){}
The vtable will be in test1.o, but not in test2.o
vtable 将在 test1.o 中,但不在 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.
这是 g++ 实现的优化,以避免必须编译会被 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.
您描述的链接错误表明您的项目中缺少虚拟方法的定义(上面示例中的 str::f)。
回答by Abrax
You may take a look at this answer to an identical question (as I understand): https://stackoverflow.com/a/1478553The link posted there explains the problem.
您可以看看这个相同问题的答案(据我所知): https://stackoverflow.com/a/1478553 那里发布的链接解释了这个问题。
For quick solving your problem you should try to code something like this:
为了快速解决您的问题,您应该尝试编写如下代码:
ImplementingClass::virtualFunctionToImplement(){...}
It helped me a lot.
ImplementingClass::virtualFunctionToImplement(){...}
这对我帮助很大。
回答by sgowd
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.
我遇到这个问题的原因是因为我已经从 cpp 文件中删除了函数的实现,但忘记从 .h 文件中删除声明。
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.
我的回答并没有专门回答你的问题,但让来这个帖子寻找答案的人知道这也是一个原因。
回答by sehe
it suggests that you fail to link the explicitly instantiated basetype public gameCore (whereas the header file forward declares it).
它表明您未能链接显式实例化的基本类型公共 gameCore(而头文件转发声明它)。
Since we know nothing about your build config/library dependencies, we can't really tell which link flags/source files are missing, but I hope the hint alone helps you fix ti.
由于我们对您的构建配置/库依赖项一无所知,因此我们无法真正判断缺少哪些链接标志/源文件,但我希望单独的提示可以帮助您修复 ti。