Template Classes

closed account (Lv0f92yv)
I have a node class defined as this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Node.h"

template <class T>Node<T>::Node(void)
{
	cout << "Node created with default value\n";
	_val = 0; //default
	left = NULL;
	right = NULL; //init the kids
}

template <class T>Node<T>::~Node(void)
{
}

template <class T>Node<T>::Node( T val )
{
	//cout << "Node created with val " << val << "\n";
	_val = val;
	right = NULL;
	left = NULL; //init the kids
}


In my application code (another .cpp file), I am trying to find a node in my tree and store it:

Node<int>* n = tree->find( val );

This line causes: error LNK2019: unresolved external symbol "public: class Node<int> * __thiscall BST<int>::find(int)" (?find@?$BST@H@@QAEPAV?$Node@H@@H@Z) referenced in function _main error.

My tree is defined as this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include "BST.h"

template <class T> BST<T>::BST(void)
{
	//_root = new Node(); //default constructor
	_root = NULL;
}

template <class T> BST<T>::BST( T val )
{
	_root = new Node<T>( val );
}

template <class T> BST<T>::~BST(void)
{
}

template <class T> Node<T>* BST<T>::find( T val )
{
	if ( _root == NULL )
		return NULL; //nothing in tree, app code must check this
	return findNode( val, _root );
}

template <class T> Node<T>* BST<T>::findNode( T val, Node<T>* n )
{
	if ( n == NULL )
		return NULL; //not in tree

	if ( val == n->_val )
		return n; //found it

	//determine which child to check next
	if ( val < n->_val )
		return findNode( val, n->left );
	if ( val > n->_val )
		return findNode( val, n->right );
}

template <class T> void BST<T>::add( Node<T>* newNode )
{
	if ( _root == NULL )
	{
		_root = newNode;
		//cout << "Root assigned " << newNode->_val << "\n";
		return;
	}
	add( newNode, _root );
}

template <class T> void BST<T>::add( Node<T>* newNode, Node<T>* check )
{

	if ( newNode->_val > check->_val && check->right == NULL )
		check->right = newNode;
	else if ( newNode->_val > check->_val )
		add( newNode, check->right );

	if ( newNode->_val <= check->_val && check->left == NULL )
		check->left = newNode;
	else if ( newNode->_val <= check->_val )
		add( newNode, check->left );
}
template <class T> void BST<T>::print( Node<T>* n )
{
	//print the tree here
	if ( n == NULL )
		return; //base case

	//in order print
	print(n->left);
	cout << n->_val << "::";
	print(n->right);
}


Why can I not make a node like that in my application code?
You can't have the template functions in a separate .cpp file, they must go in the header file with the class.
closed account (Lv0f92yv)
Ahh thank you. I switched all function definitions to the header file, works as expected.

Thanks - this cleared up a lot of mystery about templates for me.

You CAN have the template class definition and implementation separated!


Try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//: node.h
#if !defined _NODE_H_
#define _NODE_H_

template <class T>Node
{
     //: Code for your class.....
};

//Then do this: before the endif directive include your .cpp file...

#include "Node.cpp"

#endif  //: ~ 


1
2
3
4
//: Node.cpp

//: The definition code goes here but do not include "Node.h" in this source file


There are some other things to do to keep the implementacion and definition separeted with templates but some depends on the compiler:

What? WHAT?

Including cpp files is evil on this forum. Sorry. Decent reasons why as well. Anyone here care to explain?

I personally consider most evil features to be useful, but that's only because I generally don't mess them up catastrophically (I have safeguards against it). However, it's very easy to mess them up, and the time spend debugging an error caused by the may very well exceed the time saved by using that feature.

-Albatross
Last edited on
Why do you advice to locate template implementation in separate cpp file?

It should be header file, but idea the same. Implementation and declaration is situated in separate files, but I prefer use headers file for templates
Well i DO NOT advice just wanted to point out that such thing is posible if ever wanted to separate both files... It should be handle with care tho!

There's another way, which i wont't say but for those curious look up the keyword export and read on the subject if u like...

Things are being done to fix that with templates, implementation and declaration the way of C++.
Sometimes ago I've tried to use export for this goal, but compiler just said: sorry export keyword is reserved, but not implemented.

So there is a possibility to break compilation compatibility
closed account (Lv0f92yv)
It's good to know that that feature is provided, but I have read that including .cpp files in headers is bad practice in many different areas, so for this project I'll stick to doing everything in headers.

Another question - about operator overloading.

I have overloaded the << operator as follows in my CustomClass class:

1
2
3
4
string CustomClass::operator << (CustomClass cc)
{
	return cc.val;
}


where val is a string object in CustomClass.

, and am trying to cout << an instance of this class using: cout << val << "::";

were val is the instance of CustomClass provided in a Node<CustomClass> object passed to the function that contains this cout.

What do I need to do so that the cout << of the CustomClass object works?
As a separate method. If you need to access private members, variables friend it in your class.

1
2
3
4
ostream& operator<<(ostream& s, const CusmtomClass & cc){
s << cc.val;
return s;
}



I am not shure, but I think it should help. Declare operator<< member as a friend.
1
2
3
4
5
friend std::ostream& operator<<(std::ostream& stream, Node<CustomClass>& destination)
{

return stream;
}
Last edited on
closed account (Lv0f92yv)
Indeed, tried this and it works. Thanks. Not sure I understand the notation, with the ostream parameters and all. Though it makes sense - since the usual << is a bitwise operation, and doesn't deal with io streams.

Now why is it that when I create a Node object with:

1
2
3
4
5
6
7
8
9
10
11
12
13
        BST<CustomClass> cbst;
	CustomClass cc( "abc" );
	CustomClass cc2( "d" );
	CustomClass cc3( "efg" );
	CustomClass cc4( "sdybvsdyb" );
	CustomClass cc5( "sudhsduhsudh" );

	cout << cc << "\n"; 
	cbst.add( new Node<CustomClass>( cc ) );
	cbst.add( new Node<CustomClass>( cc2 ) );
	cbst.add( new Node<CustomClass>( cc3 ) );
	cbst.add( new Node<CustomClass>( cc4 ) );
	cbst.add( new Node<CustomClass>( cc5 ) );


my output uses values based on the default constructor for the CustomClass objects instead of the strings assigned in the overloaded constructor? The cout << cc << "\n"; works fine, prints abc to the screen. The cbst prints, however, print the value assigned from the default constructor of the CustomClass objects. Anyone know why this is?

Edit: I think I need to pass these in by reference, but why?
Last edited on
Constructors don't overload (in the sense that a virtual method is overloadable). You either create an object of the derived type or the base type. The appropriate constructor is called.

I don't understand. What output you getting? And what does CustomClass do? Or is CustomClass only a placeholder
Last edited on
closed account (Lv0f92yv)
For output I was seeing only the last CustomClass object that I added value print for EACH of the node objects.

The CustomClass is a class I write that simply has a string variable, initialized in the constructor to the strings I pass in when creating the object. I have fixed my problem by passing the CustomClass object by reference to the Node constructor.

Thanks for the help all who have replied.
Last edited on
Topic archived. No new replies allowed.