Monday, December 21, 2009

How to do the definition of a template class in .h file and implementation of the template classes in .cpp file?

The common procedure in C++ is to put class definition in a C++ header file and the implementation in a C++ source file. Then the source file is made part of the project, meaning compiled separately. But when we implement this procedure for template class, some compilation and linking problem will arise.

1. Compilation

PROBLEM

Sample Code:

Template Class Header File

// TestTemp.h

#ifndef _TESTTEMP_H_

#define _TESTTEMP_H_

template

class TestTemp

{

public:

TestTemp();

void SetValue( T obj_i );

T Getalue();

private:

T m_Obj;

};

#endif

Template Class Source File

// TestTemp.cpp

#include "TestTemp.h"

TestTemp::TestTemp()

{

}

void TestTemp::SetValue( T obj_i )

{

}

T TestTemp::Getalue()

{

return m_Obj;

}

If you try to implement the template class like a normal class implementation as shown above, it will generate a set of compilation errors such as

: error C2955: 'TestTemp' : use of class template requires template argument list

: error C2065: 'T' : undeclared identifier

REASON

In this case, the compiler doesn’t know about the object type. So it will not compile.

SOLUTION

To compile this class without any errors you need to put the template specific declaration in .cpp file also as shown below.

Sample Code:

Template Class Header File

// TestTemp.h

#ifndef _TESTTEMP_H_

#define _TESTTEMP_H_

template

class TestTemp

{

public:

TestTemp();

void SetValue( T obj_i );

T Getalue();

private:

T m_Obj;

};

#endif

Template Class Source File

// TestTemp.cpp

#include "TestTemp.h"

template

TestTemp::TestTemp()

{

}

template

void TestTemp::SetValue( T obj_i )

{

}

template

T TestTemp::Getalue()

{

return m_Obj;

}

2. Linking

PROBLEM

With the above code, after resolving all the compilation error you may get some link errors while you create an object of this class in any file other than the TestTemp.cpp file.

Sample Code:

Client Source File

// Client.cpp

#include "TestTemp.h"

:

TestTemp TempObj;

:

: error LNK2001: unresolved external symbol "public: __thiscall TestTemp::TestTemp(void)" (??0?$TestTemp@H@@QAE@XZ)

REASON

When the compiler does encounter a declaration of a TestTemp object of some specific type, e.g., int, it must have access to the template implementation source. Otherwise, it will have no idea how to construct the TestTemp member functions. And if you have put the implementation in a source (TestTemp.cpp) file and made it a separate part of the project, the compiler will not be able to find it when it is trying to compile the client source file. And #including the header file (TestTemp.h) will not sufficient at that time. That only tells the compiler how to allocate for the object data, and how to build the calls to the member functions, not how to build the member functions. And again, the compiler won’t complain. It will assume that these functions are provided elsewhere, and leave it to the linker to find them. So, when it’s time to link you will get "unresolved references" to any of the Class member functions that are not defined "inline" in the class definition.

SOULTION

There are different methods to solve this problem. You can select from any of these methods which is suitable for your application design.

METHOD1:

You can create the object of template class in the same file source file where it is implemented (TestTemp.cpp). So that there is no need to link the object creation code with its actual implementation in some other file. This will cause the compiler to compile these particular types, so the associated class member functions will be available at link time.

Sample Code:

Template Class Header File

// TestTemp.h

#ifndef _TESTTEMP_H_

#define _TESTTEMP_H_

template

class TestTemp

{

public:

TestTemp();

void SetValue( T obj_i );

T Getalue();

private:

T m_Obj;

};

#endif

Template Class Source File

// TestTemp.cpp

#include "TestTemp.h"

template

TestTemp::TestTemp()

{

}

template

void TestTemp::SetValue( T obj_i )

{

}

template

T TestTemp::Getalue()

{

return m_Obj;

}

void TemporaryFunction ()

{

TestTemp TempObj;

}

Client Source File

// Client.cpp

#include "TestTemp.h"

:

TestTemp TempObj;

TempObj.SetValue( 2 );

int nValue = TempObj.Getalue();

:

No need to call this TemporaryFunction() function, it’s just to avoid link error.

METHODE 2

You can #include the source file that implements your template class in your client source file.

Sample Code:

Template Class Header File

// TestTemp.h

#ifndef _TESTTEMP_H_

#define _TESTTEMP_H_

template

class TestTemp

{

public:

TestTemp();

void SetValue( T obj_i );

T Getalue();

private:

T m_Obj;

};

#endif

Template Class Source File

// TestTemp.cpp

#include "TestTemp.h"

template

TestTemp::TestTemp()

{

}

template

void TestTemp::SetValue( T obj_i )

{

}

template

T TestTemp::Getalue()

{

return m_Obj;

}

Client Source File

// Client.cpp

#include "TestTemp.h"

#include "TestTemp.cpp"

:

TestTemp TempObj;

TempObj.SetValue( 2 );

int nValue = TempObj.Getalue();

:

METHODE 3

You can #include the source file that implements your template class (TestTemp.cpp) in your header file that defines the template class (TestTemp.h) and remove the source file from the project, not from the folder.

Sample Code:

Template Class Header File

// TestTemp.h

#ifndef _TESTTEMP_H_

#define _TESTTEMP_H_

template

class TestTemp

{

public:

TestTemp();

void SetValue( T obj_i );

T Getalue();

private:

T m_Obj;

};

#include "TestTemp.cpp"

#endif

Template Class Source File

// TestTemp.cpp

#include "TestTemp.h"

template

TestTemp::TestTemp()

{

}

template

void TestTemp::SetValue( T obj_i )

{

}

template

T TestTemp::Getalue()

{

return m_Obj;

}

Client Source File

// Client.cpp

#include "TestTemp.h"

:

TestTemp TempObj;

TempObj.SetValue( 2 );

int nValue = TempObj.Getalue();

:

No comments:

Post a Comment