c++ linker linker-errors vtable

c++ - Referencia no definida a ''vtable para xxx''



linker linker-errors (6)

El primer conjunto de errores, para el vtable faltante, se debe a que no implementa takeaway::textualGame() ; en su lugar, implementa una función no miembro, textualGame() . Creo que agregar el material faltante takeaway:: lo solucionará.

La causa del último error es que estás llamando a una función virtual, initialData() , del constructor de gameCore . En esta etapa, las funciones virtuales se envían según el tipo que se está construyendo actualmente ( gameCore ), no la clase más derivada ( takeaway ). Esta función particular es puramente virtual, por lo que llamarla aquí proporciona un comportamiento indefinido.

Dos posibles soluciones:

  • Mueva el código de inicialización para gameCore fuera del constructor y en una función de inicialización separada, que debe gameCore después de que el objeto esté completamente construido; o
  • Separe gameCore en dos clases: una interfaz abstracta que se implementará para takeaway , y una clase concreta que contenga el estado. takeaway primero y luego páselo (a través de una referencia a la clase de interfaz) al constructor de la clase concreta.

Recomendaría el segundo, ya que es un movimiento hacia clases más pequeñas y un acoplamiento más flexible, y será más difícil usar las clases incorrectamente. El primero es más propenso a errores, ya que no hay forma de asegurarse de que la función de inicialización se invoque correctamente.

Un último punto: el destructor de una clase base normalmente debe ser virtual (para permitir la eliminación polimórfica) o estar protegido (para evitar la eliminación polimórfica no válida).

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

Sigo recibiendo este error del enlazador, sé que tiene algo que ver con las funciones en línea que obtienen un vtable almacenado temporalmente. Pero lo que eso implica no estoy seguro. Supongo que tiene algo que ver con cómo llamo al constructor de gameCore en la lista de inicio de takeaway.cpp

Tengo una clase de plantilla (gameCore.h) y una clase (takeaway.cpp) que hereda de gameCore. El error de vtable se llama 3 veces 1) en el constructor takeaways 2) takeaways destructor 3) en el constructor de gameCores.

Estoy usando G ++ Aquí está el código: (sé que puede parecer difícil de leer, pero he marcado claramente donde se producen los errores) 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


Puede echarle un vistazo a esta respuesta a una pregunta idéntica (según tengo entendido): https://.com/a/1478553 El enlace publicado allí explica el problema.

Para solucionar rápidamente su problema, debería intentar codificar algo como esto:

ImplementingClass::virtualFunctionToImplement(){...} Me ayudó mucho.


Si una clase define métodos virtuales fuera de esa clase, g ++ genera el vtable solo en el archivo objeto que contiene la definición fuera de clase del método virtual que se declaró primero:

//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(){}

El vtable estará en test1.o, pero no en test2.o

Esta es una optimización de los implementos de g ++ para evitar tener que compilar métodos virtuales definidos en la clase que serían arrastrados por el vtable.

El error de enlace que describes sugiere que la definición de un método virtual (str :: f en el ejemplo anterior) falta en tu proyecto.


Uno o más de sus archivos .cpp no ​​están siendo vinculados, o algunas funciones no en línea en alguna clase no están definidas. En particular, no se puede encontrar la implementación de takeaway::textualGame() . Tenga en cuenta que ha definido un textualGame() en toplevel, pero esto es distinto de una implementación takeaway::textualGame() . Probablemente se olvidó de la información takeaway:: allí.

Lo que significa el error es que el vinculador no puede encontrar el "vtable" para una clase: cada clase con funciones virtuales tiene una estructura de datos "vtable" asociada a ella. En GCC, este vtable se genera en el mismo archivo .cpp que el primer miembro de la clase que no está en línea; si no hay miembros que no estén en línea, creo que se generará siempre que crea una instancia de la clase, creo. Por lo tanto, es probable que falles al vincular el archivo .cpp con el primer miembro no en línea incluido en la lista, o nunca definir ese miembro en primer lugar.


sugiere que no se pueda vincular el juego público de base de datos explícitamente instanciado gameCore (mientras que el archivo de cabecera forward lo declara).

Dado que no sabemos nada sobre las dependencias de la configuración de su compilación / biblioteca, no podemos decir realmente qué banderas de enlace / archivos fuente faltan, pero espero que la sugerencia por sí sola lo ayude a solucionarlo.


Falta la implementación de una función en clase

La razón por la que me enfrenté a este problema fue porque eliminé la implementación de la función del archivo cpp, pero olvidé eliminar la declaración del archivo .h.

Mi respuesta no responde específicamente a su pregunta, pero permite que las personas que acuden a este hilo en busca de respuestas sepan que esto también puede ser una causa.