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)とgameCoreから継承するクラス(takeaway.cpp)がありますvtableエラーは3回呼び出されます1)takeawaysコンストラクター2)takeaways destructor 3)gameCoresコンストラクター
G ++を使用しています。コードは次のとおりです(読みにくいと思われるかもしれませんが、エラーが発生した場所を正確にマークしました)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
不足しているvtableの最初のエラーセットは、takeaway::textualGame()
;を実装していないために発生します。代わりに、非メンバー関数textualGame()
を実装します。欠落している_takeaway::
_を追加すると修正されると思います。
最後のエラーの原因は、gameCore
のコンストラクターから仮想関数initialData()
を呼び出していることです。この段階で、仮想関数は現在構築されているタイプ(gameCore
)、not最も派生したクラス(takeaway
)に従ってディスパッチされます。この特定の関数は純粋な仮想であるため、ここで呼び出すと未定義の動作になります。
2つの可能な解決策:
gameCore
の初期化コードをコンストラクターから別の初期化関数に移動します。この関数はafterと呼ばれる必要があり、オブジェクトは完全に構築されています。またはgameCore
を2つのクラスに分離します。takeaway
によって実装される抽象インターフェイスと、状態を含む具体的なクラスです。最初にtakeaway
を構築し、次に(インターフェイスクラスへの参照を介して)具象クラスのコンストラクタに渡します。2番目の方法をお勧めします。これは、クラスが小さくなり、結合が緩くなる傾向があり、クラスを誤って使用するのが難しくなるためです。 1つ目は、初期化関数が正しく呼び出されることを確認する方法がないため、エラーが発生しやすくなります。
最後の1つのポイント:基本クラスのデストラクタは、通常、仮想(多態的削除を許可する)か、保護(無効な多態的削除を防止する)する必要があります。
1つ以上の.cppファイルがリンクされていないか、一部のクラスの一部の非インライン関数が定義されていません。特に、takeaway::textualGame()
の実装が見つかりません。トップレベルでtextualGame()
を定義したことに注意してください。ただし、これはtakeaway::textualGame()
実装とは異なります。おそらくtakeaway::
そこ。
エラーが意味することは、リンカがクラスの「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にはありません。
これは、vtableに取り込まれるクラス内で定義された仮想メソッドをコンパイルする必要を避けるために、g ++が実装する最適化です。
説明するリンクエラーは、仮想メソッドの定義(上記の例ではstr :: f)がプロジェクトにないことを示唆しています。
同一の質問に対するこの回答をご覧ください(私が理解しているように): https://stackoverflow.com/a/147855 そこに投稿されたリンクは問題を説明しています。
問題をすばやく解決するには、次のようなコードを作成する必要があります。
ImplementingClass::virtualFunctionToImplement(){...}
それは私を大いに助けてくれました。
クラスの関数の実装がありません
この問題に直面した理由は、cppファイルから関数の実装を削除したが、.hファイルから宣言を削除するのを忘れていたためです。
私の答えはあなたの質問に具体的に答えているわけではありませんが、答えを探しているこのスレッドに来た人は、これが原因の1つであることを知っています。
明示的にインスタンス化されたベースタイプのパブリックgameCoreのリンクに失敗することを示唆しています(一方、ヘッダーファイルは前方宣言しています)。
ビルド構成/ライブラリの依存関係については何も知らないため、どのリンクフラグ/ソースファイルが欠落しているかはわかりませんが、ヒントだけでtiを修正できると思います。