This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
As long as I don't call the function, everything is fine, but once I call the function I get an unresolved external symbol. All of my classes are in the SSE namespace (my own) and have worked fine up until now. Let me show.
#include "SDL.h"
#include "Game.h"
#include "GameObject.h"
#include <tchar.h>
SSE::Game Pong;
int _tmain(int argc, char* argv[])
{
SSE::GameObject* object;
Pong.Initialize("Pong!");
object = Pong.Objects().ObjectCreate<SSE::GameObject>();
while (!Pong.bQuit)
{
Pong.Update();
Pong.Draw();
}
return 0;
}
This is where I call the function. Game is a class that runs the behind the scenes work for me (everything's fine with that class), Game.Objects() returns the Game's ObjectManager which is in charge of creating and deleting objects as well as giving objects their components. ObjectCreate is a template function which returns a pointer to the new object created.
From the ObjectManager's .cpp file:
template <class G>G* ObjectManager::ObjectCreate()
{
ObjectList* tempObjList;
tempObjList = new tempObjList();
tempObjList->objectType = G->ClassName();
tempObjList->objectTypeNumber = 0;
for (unsigned int i = 0; i < v_objList.size(); i++;)
{
if (v_objList[i]->objectType == tempObjList->objectType)
tempObjList->objectTypeNumber++;
}
tempObjList->gameObject = new G(tempObjList->objectType + "_" + tempObjList->objectTypeNumber);
v_objList.push_back(tempObjList);
if (v_objList.back() != tempObjList)
{
delete tempObjList;
return NULL;
}
return v_objList.back();
}
This assigns a unique name for the new GameObject and creates it in memory, then stores it into a vector. One other thing to mention is I've been getting this unresolved external symbol error for many of the ObjectManager and GameObject functions similar to this one, but just the same only if I call them in code.
Just for reference, the error is:
Error 2 error LNK2019: unresolved external symbol "public: class SSE::GameObject * __thiscall SSE::ObjectManager::ObjectCreate(void)" (??$ObjectCreate#VGameObject#SSE###ObjectManager#SSE##QAEPAVGameObject#1#XZ) referenced in function _SDL_main C:\SDL\SimpleStateEngine\SSE\main.obj SSE
Let me know if you need anything else, I've been searching for hours.
You've fallen into the common trap of defining a template function in a cpp file.
You need to define the function anywhere the calling code can see it, because it's only instantiated when it's used with specific template parameters.
Your other option is to instantiate it specifically as ObjectCreate<SSE::GameObject> in your cpp file.
What you've done is define how it could be instantiated in ObjectManager.cpp and called it as if it were instantiated in another cpp file.
Related
This question already has answers here:
C++ inlining class methods causes undefined reference
(3 answers)
When should I write the keyword 'inline' for a function/method?
(16 answers)
Closed 2 years ago.
I'm trying to have a class call a function from an inherited class however whenever I do I get an unresolved external error LNK2019. I'm confused to why this is happening as all of the files appear to be properly included, I haven't overridden the function & Visual Studio doesn't complain about it prior to compiling.
I've tried:
Running the replacing the function call with the actual code, this fixes one of the two errors but I still get an unresolved external as the functions in question are calling another function from another class.
Messing around with namespaces, as the inherited class is under a separate namespace I thought that was the problem e.g. Memory::Allocate(...).
Directly calling the class function, so instead of Allocate(...) I tried Memory::GlobalMemoryUser::Allocate(...)
Calling the function using this->...
Relevant code from GlobalMemoryUser.h
#include "MemoryManager"
namespace Memory
{
namespace Internal
{
extern MemoryManager* GlobalMemoryManager;
{
class GlobalMemoryUser
{
public:
// Allocator and deallocator
inline const void* Allocate(size_t, const char* user);
inline const void DeAllocate(void*);
private:
// A pointer to the global memory manager
Internal::MemoryManager* GlobalMemoryManager;
};
}
Relevant code from GlobalMemoryManager.cpp
#include "GlobalMemoryUser.h"
namespace Memory {
const void* GlobalMemoryUser::Allocate(size_t size, const char* user)
{
return GlobalMemoryManager->Allocate(size, user);
}
const void GlobalMemoryUser::DeAllocate(void* p)
{
GlobalMemoryManager->DeAllocate(p);
}
}
Relevant code from System Manager.h
#include "GlobalMemoryUser.h"
namespace ECS
{
class SystemManager : public Memory::GlobalMemoryUser
{
// Constructor and Deconstructor
SystemManager();
~SystemManager();
};
}
Relevant code from SystemManager.cpp
#include "SystemManager.h"
namespace ECS
{
SystemManager::SystemManager()
{
systemAllocator = new Memory::LinearAllocator(ECS_SYSTEM_MEMORYBUFFERSIZE, Allocate(ECS_SYSTEM_MEMORYBUFFERSIZE, "SystemManager"));
}
SystemManager::~SystemManager()
{
for (std::vector<ISystem*>::reverse_iterator it = systemWorkOrder.rbegin(); it != systemWorkOrder.rend(); it++)
{
(*it)->~ISystem();
*it = nullptr;
}
systemWorkOrder.clear();
systemsTable.clear();
DeAllocate((void*)systemAllocator->GetUsedMemoryStart());
delete systemAllocator;
systemAllocator = nullptr;
}
}
The errors in question happen within the constructor and deconstructor for the system manager when trying to call the allocator and deallocator from the GlobalMemoryUser parent class.
Exact Error Message:
LNK2019 unresolved external symbol "public: void const * __cdecl Memory::GlobalMemoryUser::Allocate(unsigned __int64,char const *)" (?Allocate#GlobalMemoryUser#Memory##QEAAPEBX_KPEBD#Z) referenced in function "public: __cdecl ECS::SystemManager::SystemManager(void)" (??0SystemManager#ECS##QEAA#XZ)
I've spent the last 2 days searching for and implementing the answers from similar questions into my code with little success. I have an API that is an external .dll (windows) and I have the header file included into my .cpp file to reference the API.
However I have this issue that no matter what I do, I always get an unresolved external symbol that references this line in my .h file. Yes, I have used Google and modified the answers I found into my code, with no success.
Foo.h
Class Foo {
public:
static Foo* Interface_Get(char* dllfilename);
Foo.cpp
// I declare this just underneath the #include "Foo.h" header
Foo *foo = 0;
Inside my main function I declare it as this (along with some other functions that are fine).
//This has already been created and both Header and .dll are in the same directory.
Foo::Interface_Get("bar.dll");
And I get this error
error LNK2019: unresolved external symbol
"public: static class Foo * __cdecl Foo::Interface_Get(char *)"
I've tried everything I know (This is my first .dll creation experience) I have a feeling I am missing something painfully obvious, but for the life of me I cannot see it.
Entire Foo.cpp
#include "Foo.h"
Foo* Foo::Interface_Get(char* dllfilename); //May not be redeclared outside class error
Foo* foo = 0;
bool Frame()
{
if (foo->Key_Down(DIK_ESCAPE))
return false;
return true;
}
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
foo->Interface_Get("bar.dll");
foo->System_SetState(grSTATE_FRAME, Frame);
foo->System_SetState(grSTATE_WINDOWED, true);
foo->System_SetState(grSTATE_KEYBOARD, true);
foo->System_Initiate();
foo->System_Start();
foo->System_Shutdown();
foo->Inferface_Release();
return 0;
}
This question explains common problems, and in your case it's (probably) a combination of:
(possibly) forgetting to implement the function
forgetting __declspec(dllexport)
forgetting to link against the library
You need to provide function definition for Interface_Get(char* dllfilename); if you haven't done that.
This only redeclares function again, you need to provide function like below format with {}
Foo* Foo::Interface_Get(char* dllfilename); //May not be redeclared outside class error
Foo.cpp
Foo* Foo::Interface_Get(char* dllfilename)
{
//....
return new Foo();
}
I am trying to create a new instance of a class, however I am receiving a LNK2001 unresolved external symbol error when I attempt to compile my code.
As far as I can tell I have written and included the class in exactly the same manner as I included another class, in both cases -
#include "class.h" // In main.cpp
class Class { // In class.h
private:
// etc.
public:
Class();
~Class();
// etc.
};
#include "class.h" // In class.cpp
Is there a common / likely cause of these errors, or a good way I might go about finding the source of the issue?
Edit: The error is
"Error 1 error LNK2019: unresolved external symbol "class Max
__cdecl max(void)" (?max##YA?AVMax##XZ) referenced in function _main main.obj Racing "
Edit: In both cases, a class is implemented across a .h and a .cpp file included in a project. The error is only appearing with one class.
Somewhere you have written this:
Max max();
What you intended was to declare a variable max of type Max.
C++ thinks you intend to declare a function max which returns an object of type Max. This is what it is looking for.
If you just say this:
Max max;
The issue will go away.
Edit: This only occurs with constructors which take no arguments. If the constructor takes arguments, C++ can see from the parameters (which will be rvalues, e.g. constants or expressions) that it is an instantiation of the class not a function declaration.
Max max(5); // Clearly cannot be a function, because 5 is an rvalue
Or
Max max(int); // Clearly cannot be an instantiation, because int is a type
But if the constructor takes no arguments, to distinguish between them, you have to drop the brackets if you are instantiating.
I have a problem with generics in c++.I have two Matrix.h and Matrix.cpp files.Here is files:
#pragma once
template<class T>
class Matrix
{
public:
static T** addSub(int size,T** firstMatrix,T** secondMatrix,int operation);
}
and Matrix.cpp
#include "Martix.h"
template<class T>
static T** Matrix<T>::addSub( int n,T **firstMatrix,T **secondMatrix,int operation)
{
//variable for saving result operation
T **result = new T*[n];
//create result matrix
for( int i=0;i<n;i++)
result[i] = new T[n];
//calculate result
for( int i=0;i<n;i++)
for(int j=0;j<n;j++)
result[i][j] =
(operation == 1) ? firstMatrix[i][j] + secondMatrix[i][j]:
firstMatrix[i][j] - secondMatrix[i][j];
return result;
}
when I run these I get the below error:
Error 1 error LNK2019: unresolved external symbol "public: static int * * __cdecl Matrix<int>::addSub(int,int * *,int * *,int)" (?addSub#?$Matrix#H##SAPAPAHHPAPAH0H#Z) referenced in function "public: static int * * __cdecl Matrix<int>::strassenMultiply(int,int * *,int * *)" (?strassenMultiply#?$Matrix#H##SAPAPAHHPAPAH0#Z) C:\Users\ba.mehrabi\Desktop\Matrix\matrixMultiplication\main.obj matrixMultiplication
what is the problem?
Unfortunately, you can't have the declaration of a template class in the *.cpp files. The full definition has to stay in the header file. This is a rule of many C++ compilers.
See this: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
A template is not a class or a function. A template is a "pattern"
that the compiler uses to generate a family of classes or functions.
In order for the compiler to generate the code, it must see both
the template definition (not just declaration) and the specific
types/whatever used to "fill in" the template. For example, if you're
trying to use a Foo, the compiler must see both the Foo template
and the fact that you're trying to make a specific Foo.
Your compiler probably doesn't remember the details of one .cpp
file while it is compiling another .cpp file. It could, but most do
not and if you are reading this FAQ, it almost definitely does not.
BTW this is called the "separate compilation model."
The link has a workaround, but keep in mind that a template is a glorified macro so the header file is probably the best place for it.
The poster of this SO post shows a demonstration of the workaround.
First of all, the definition of functions of a class template, should go in the header itself.
Second, if you define the static member function out of class (though in the header itself), then don't use the static keyword (in the definition). It only needed in the declaration only.
Add
template Matrix<int>;
at the end of your cpp file and it will work. But you need to learn a few things about templates, otherwise you'll have to deal with lots of issues you don't understand.
I want to have some data cache which contains some objects which I can update over an UpdateCache function. However, I'm getting problems with a LNK2001 followed by a LNK1120.
HeaderFile.h
#ifndef headerfile_included
#define headerfile_included
#include <vector>
struct MyObject {
unsigned int A;
unsigned int B;
};
class MyClass {
private:
static std::vector<MyObject> myObjectCache;
public:
static void UpdateCache ();
};
#endif
CodeFile.cpp
#include "HeaderFile.h"
void MyClass::UpdateCache () {
myObjectCache.clear();
/* Repopulate cache with new data */
}
The error message I get from the linked is
error LNK2001: unresolved external symbol ""private: static class std::vector > MyClass::myObjectCache" (?myObjectCache#MyClass##0V?$vector#UMyObject##V?$allocator#UMyObject###std###std##A)".
fatal error LNK1120: 1 unresolved externals
My opinion is that it is some problem with the partitioning into the header file and the code file as I have had similar problems with improper partitioning. If it is again such a problem, it would be nice if you could post some rule on what to put into the header file and what into the code file since it's pretty confusing.
You need to add this to a cpp file:
std::vector<MyObject> MyClass::myObjectCache;
The reason is that as a static exists without a class ever being instantiated it needs to exist whether an instance of the class is instantiated or not. The line above creates the instance of the static and thus it exists whether or not you ever create an instance of the class itself.
Since your vector is static, essentially a global entity as far as the compiler is concerned, you need to be sure to give it a home in a compilation unit. That's why you have to do what #Goz says and do
std::vector<MyObject> MyClass::myObjectCache;