Nested Class Template

C

cyberdave

Someone please help me!

I have a template class like this:

--------------------------------------------------

template<typename T>
class List
{
public:
...

// Nested Class
class Node
{
public:
...
void setPreviousNode(Node* pnNode);
void setNextNode(Node* pnNode);

private:
// Data Members
T m_sData;
Node* m_pnPreviousNode;
Node* m_pnNextNode;
....
};

....

template<typename T>
void List<T>::Node::setPreviousNode(Node* pnNode)
{
m_pnPreviousNode = pnNode;
}

template<typename T>
void List<T>::pushBack(T sString)
{
...
pnNewNode->setPreviousNode(m_pnLastNode);
m_pnLastNode->setNextNode(pnNewNode);
...
}

....

int main()
{
List<int> i;
i.pushBack(1);
i.pushBack(2);
i.pushBack(3);
i.pushBack(4);

return 0;
}

--------------------------------------------------

I can compile it (I'm using VC++ 6.0). But when I try to link it, it
gave me:

Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setNextNode(class List<int>::Node *)"
(?setNextNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setPreviousNode(class List<int>::Node *)"
(?setPreviousNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall List<int>::Node::Node(int)" (??0Node@?$List@H@@QAE@H@Z)

I think it has something to do with my setNextNode and setPreviousNode.
Since Node is nested in the template class List, how do I pass it as a
parameter? Did I declare it correctly? Thanks.

--DK
 
C

cyberdave

give you more detail on my pushBack function:

--------------------------------------------------

template<typename T>
void List<T>::pushBack(T sString)
{
Node* pnNewNode = new Node(sString);

if (m_pnLastNode == NULL)
{
m_pnLastNode = pnNewNode;
m_pnFirstNode = pnNewNode;
}
else
{
pnNewNode->setPreviousNode(m_pnLastNode);
m_pnLastNode->setNextNode(pnNewNode);
m_pnLastNode = pnNewNode;
}
}
 
R

red floyd

Someone please help me!

I have a template class like this:

--------------------------------------------------
[redacted]

--------------------------------------------------

I can compile it (I'm using VC++ 6.0). But when I try to link it, it
gave me:

Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setNextNode(class List<int>::Node *)"
(?setNextNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setPreviousNode(class List<int>::Node *)"
(?setPreviousNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall List<int>::Node::Node(int)" (??0Node@?$List@H@@QAE@H@Z)

I think it has something to do with my setNextNode and setPreviousNode.
Since Node is nested in the template class List, how do I pass it as a
parameter? Did I declare it correctly? Thanks.

--DK

You have to put the implementation of your template classes in your
header file.

See the FAQ, inparticular 35.12 and 35.13.

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
 
G

Greg Comeau

Someone please help me!

I have a template class like this:

--------------------------------------------------
[redacted]

--------------------------------------------------

I can compile it (I'm using VC++ 6.0). But when I try to link it, it
gave me:

Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setNextNode(class List<int>::Node *)"
(?setNextNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public: void
__thiscall List<int>::Node::setPreviousNode(class List<int>::Node *)"
(?setPreviousNode@Node@?$List@H@@QAEXPAV12@@Z)
Main.obj : error LNK2001: unresolved external symbol "public:
__thiscall List<int>::Node::Node(int)" (??0Node@?$List@H@@QAE@H@Z)

I think it has something to do with my setNextNode and setPreviousNode.
Since Node is nested in the template class List, how do I pass it as a
parameter? Did I declare it correctly? Thanks.

--DK

You have to put the implementation of your template classes in your
header file.

See the FAQ, inparticular 35.12 and 35.13.

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12

And http://www.comeaucomputing.com/techtalk/templates/#whylinkerror
 
D

DK

Thanks for the reply. However, I did put my implementation in the
List.h file. Are you saying that I should put the implementation
inside of the declaration? Like this:

template<typename T>
class List
{
public:
...


// Nested Class
class Node
{
public:
...
void setPreviousNode(Node* pnNode) {...implementation ...} //
like this??
void setNextNode(Node* pnNode) {...implementation...} // like
this??


private:
// Data Members
T m_sData;
Node* m_pnPreviousNode;
Node* m_pnNextNode;
....



};
 
R

red floyd

DK said:
Thanks for the reply. However, I did put my implementation in the
List.h file.

[redacted]

Then may I suggest you post complete, compilable (but not linkable, in
your case) code, including source file indications, so that we can get a
better handle on your problem?

The error you posted seemed to indicate separate header/implementation.

Another issue to consider is that VC6 is known to have a very poor and
buggy implementation of templates.
 
D

DK

Thanks. Here is the complete List.h

//
// Filename: List.h
// Description: Declaration of the Node, Iterator, and List templates.
//
#ifndef LIST_H
#define LIST_H

#include <cassert>

using namespace std;

class Node;
template<typename T> class List;

// List
template<typename T>
class List
{
public:
// Constructor
List();

// Nested Class
class Node
{
public:
// Constructor
Node(T sData);

// Member Functions
T getData();
Node* getPreviousNode();
Node* getNextNode();
void setPreviousNode(Node* pnNode);
void setNextNode(Node* pnNode);

private:
// Data Members
T m_sData;
Node* m_pnPreviousNode;
Node* m_pnNextNode;
};

class Iterator
{
public:
// Constructor
Iterator();

// Member Function
T get() const;
void next();
void previous();
bool equals(Iterator iter) const;
Node* getPosition();
Node* getLastNode();
void setPosition(Node* pnNode);
void setLastNode(Node* pnNode);

private:
// Data Members
Node* m_pnPosition;
Node* m_pnLastNode;
};

// Member Functions
void pushBack(T sString);
void insert(Iterator iter, T sString);
Iterator erase(Iterator i);
Iterator begin();
Iterator end();

private:
// Data Members
Node* m_pnFirstNode;
Node* m_pnLastNode;
};



// Implementation
*************************************************************

// Node Template
template<typename T>
List<T>::Node::Node(T sData):m_sData(sData), m_pnNextNode(NULL),
m_pnPreviousNode(NULL) {}

template<typename T>
T List<T>::Node::getData()
{
return m_sData;
}

template<typename T>
List<T>::Node* List<T>::Node::getPreviousNode()
{
return m_pnPreviousNode;
}

template<typename T>
List<T>::Node* List<T>::Node::getNextNode()
{
return m_pnNextNode;
}

template<typename T>
void List<T>::Node::setPreviousNode(Node* pnNode)
{
m_pnPreviousNode = pnNode;
}

template<typename T>
void List<T>::Node::setNextNode(Node* pnNode)
{
m_pnNextNode = pnNode;
}

// List Template
template<typename T>
List<T>::List() : m_pnFirstNode(NULL), m_pnLastNode(NULL) {}

template<typename T>
void List<T>::pushBack(T sString)
{
Node* pnNewNode = new Node(sString);

if (m_pnLastNode == NULL)
{
m_pnLastNode = pnNewNode;
m_pnFirstNode = pnNewNode;
}
else
{
pnNewNode->setPreviousNode(m_pnLastNode);
m_pnLastNode->setNextNode(pnNewNode);
m_pnLastNode = pnNewNode;
}
}

template<typename T>
void List<T>::insert(Iterator iter, T sString)
{
if (iter.getPosition() == NULL)
{
pushBack(sString);
return;
}

Node* pnAfter = iter.getPosition();
Node* pnBefore = pnAfter->getPreviousNode();
Node* pnNewNode = new Node(sString);

pnNewNode->setPreviousNode(pnBefore);
pnNewNode->setNextNode(pnAfter);
pnAfter->setPreviousNode(pnNewNode);

if (pnBefore == NULL)
m_pnFirstNode = pnNewNode;
else
pnBefore->setNextNode(pnNewNode);
}

template<typename T>
List<T>::Iterator List<T>::erase(Iterator i)
{
Iterator iter = i;
assert(iter.getPosition() != NULL);
Node* pnRemove = iter.getPosition();
Node* pnBefore = pnRemove->getPreviousNode();
Node* pnAfter = pnRemove->getNextNode();

if (pnRemove == m_pnFirstNode)
m_pnFirstNode = pnAfter;
else
pnBefore->setNextNode(pnAfter);

if (pnRemove == m_pnLastNode)
m_pnLastNode = pnBefore;
else
pnAfter->setPreviousNode(pnBefore);

iter.setPosition(pnAfter);
delete pnRemove;

return iter;
}

template<typename T>
List<T>::Iterator List<T>::begin()
{
Iterator iter;

iter.setPosition(m_pnFirstNode);
iter.setLastNode(m_pnLastNode);

return iter;
}

template<typename T>
List<T>::Iterator List<T>::end()
{
Iterator iter;

iter.setPosition(NULL);
iter.setLastNode(m_pnLastNode);

return iter;
}

// Iterator Template
template<typename T>
List<T>::Iterator::Iterator():m_pnLastNode(NULL), m_pnPosition(NULL) {}

template<typename T>
void List<T>::Iterator::setLastNode(Node* pnNode)
{
m_pnLastNode = pnNode;
}

template<typename T>
void List<T>::Iterator::setPosition(Node* pnNode)
{
m_pnPosition = pnNode;
}

template<typename T>
List<T>::Node* List<T>::Iterator::getLastNode()
{
return m_pnLastNode;
}

template<typename T>
List<T>::Node* List<T>::Iterator::getPosition()
{
return m_pnPosition;
}

template<typename T>
T List<T>::Iterator::get() const
{
assert(m_pnPosition != NULL);
return m_pnPosition->getData();
}

template<typename T>
void List<T>::Iterator::next()
{
assert(m_pnPosition != NULL);
m_pnPosition = m_pnPosition->getNextNode();
}

template<typename T>
void List<T>::Iterator::previous()
{
if (m_pnPosition == NULL)
m_pnPosition = m_pnLastNode;
else
m_pnPosition = m_pnPosition->getNextNode();

assert(m_pnPosition != NULL);
}

template<typename T>
bool List<T>::Iterator::equals(Iterator iter) const
{
return m_pnPosition == iter.getPosition();
}

#endif
 
D

DK

I found another thing. If I put all the implementation in the
declaration, it works! So I can't separate declaration and
implementation if I have nested class within a template class??
Umm....weird....

Here is the complete List.h that works (linkable):

//
// Course: CST330 Object Oriented Programming in C++
// Auther: Ta-Wei Kuo
// Homework: Big C++, Page 816, Programming Exercise P22.6
// Due: Oct. 23, 2005
//
// Filename: List.h
// Description: Declaration of the Node, Iterator, and List templates.
//
#ifndef LIST_H
#define LIST_H

#include <cassert>

using namespace std;

class Node;
template<typename T> class List;

// List
template<typename T>
class List
{
public:
// Constructor
List()
{
m_pnFirstNode = NULL;
m_pnLastNode = NULL;
}

// Nested Class
class Node
{
public:
// Constructor
Node(T sData)
{
m_sData = sData;
m_pnNextNode = NULL;
m_pnPreviousNode = NULL;
}


// Member Functions
T getData() { return m_sData; }
Node* getPreviousNode() { return m_pnPreviousNode; }
Node* getNextNode() { return m_pnNextNode; }
void setPreviousNode(Node* pnNode) { m_pnPreviousNode = pnNode;
}
void setNextNode(Node* pnNode) { m_pnNextNode = pnNode; }

private:
// Data Members
T m_sData;
Node* m_pnPreviousNode;
Node* m_pnNextNode;
};

class Iterator
{
public:
// Constructor
Iterator()
{
m_pnLastNode = NULL;
m_pnPosition = NULL;
}

// Member Function
T get() const
{
assert(m_pnPosition != NULL);
return m_pnPosition->getData();
}

void next()
{
assert(m_pnPosition != NULL);
m_pnPosition = m_pnPosition->getNextNode();

}

void previous()
{
if (m_pnPosition == NULL)
m_pnPosition = m_pnLastNode;
else
m_pnPosition = m_pnPosition->getNextNode();

assert(m_pnPosition != NULL);
}

bool equals(Iterator iter) const { return m_pnPosition ==
iter.getPosition(); }
Node* getPosition() { return m_pnPosition; }
Node* getLastNode() { return m_pnLastNode; }
void setPosition(Node* pnNode) { m_pnPosition = pnNode; }
void setLastNode(Node* pnNode) { m_pnLastNode = pnNode; }

// Overloaded Operator
//ostream& operator<<(const Iterator& iter);

private:
// Data Members
Node* m_pnPosition;
Node* m_pnLastNode;
};

// Member Functions
void pushBack(T sString)
{
Node* pnNewNode = new Node(sString);

if (m_pnLastNode == NULL)
{
m_pnLastNode = pnNewNode;
m_pnFirstNode = pnNewNode;
}
else
{
pnNewNode->setPreviousNode(m_pnLastNode);
m_pnLastNode->setNextNode(pnNewNode);
m_pnLastNode = pnNewNode;
}
}

void insert(Iterator iter, T sString)
{
if (iter.getPosition() == NULL)
{
pushBack(sString);
return;
}

Node* pnAfter = iter.getPosition();
Node* pnBefore = pnAfter->getPreviousNode();
Node* pnNewNode = new Node(sString);

pnNewNode->setPreviousNode(pnBefore);
pnNewNode->setNextNode(pnAfter);
pnAfter->setPreviousNode(pnNewNode);

if (pnBefore == NULL)
m_pnFirstNode = pnNewNode;
else
pnBefore->setNextNode(pnNewNode);

}

Iterator erase(Iterator i)
{
Iterator iter = i;
assert(iter.getPosition() != NULL);
Node* pnRemove = iter.getPosition();
Node* pnBefore = pnRemove->getPreviousNode();
Node* pnAfter = pnRemove->getNextNode();

if (pnRemove == m_pnFirstNode)
m_pnFirstNode = pnAfter;
else
pnBefore->setNextNode(pnAfter);

if (pnRemove == m_pnLastNode)
m_pnLastNode = pnBefore;
else
pnAfter->setPreviousNode(pnBefore);

iter.setPosition(pnAfter);
delete pnRemove;

return iter;
}

Iterator begin()
{
Iterator iter;

iter.setPosition(m_pnFirstNode);
iter.setLastNode(m_pnLastNode);

return iter;
}

Iterator end()
{
Iterator iter;

iter.setPosition(NULL);
iter.setLastNode(m_pnLastNode);

return iter;
}

private:
// Data Members
Node* m_pnFirstNode;
Node* m_pnLastNode;
};

#endif
 
D

DK

I found another thing. If I put all the implementation in the
declaration, it works! So I can't separate declaration and
implementation if I have nested class within a template class??
Umm....weird....


Here is the complete List.h that works (linkable):


//
// Filename: List.h
// Description: Declaration of the Node, Iterator, and List templates.
//
#ifndef LIST_H
#define LIST_H


#include <cassert>


using namespace std;


class Node;
template<typename T> class List;


// List
template<typename T>
class List
{
public:
// Constructor
List()
{
m_pnFirstNode = NULL;
m_pnLastNode = NULL;
}


// Nested Class
class Node
{
public:
// Constructor
Node(T sData)
{
m_sData = sData;
m_pnNextNode = NULL;
m_pnPreviousNode = NULL;
}


// Member Functions
T getData() { return m_sData; }
Node* getPreviousNode() { return m_pnPreviousNode; }
Node* getNextNode() { return m_pnNextNode; }
void setPreviousNode(Node* pnNode) { m_pnPreviousNode = pnNode;



}


void setNextNode(Node* pnNode) { m_pnNextNode = pnNode; }

private:
// Data Members
T m_sData;
Node* m_pnPreviousNode;
Node* m_pnNextNode;
};


class Iterator
{
public:
// Constructor
Iterator()
{
m_pnLastNode = NULL;
m_pnPosition = NULL;
}


// Member Function
T get() const
{
assert(m_pnPosition != NULL);
return m_pnPosition->getData();
}


void next()
{
assert(m_pnPosition != NULL);
m_pnPosition = m_pnPosition->getNextNode();


}


void previous()
{
if (m_pnPosition == NULL)
m_pnPosition = m_pnLastNode;
else
m_pnPosition = m_pnPosition->getNextNode();


assert(m_pnPosition != NULL);
}


bool equals(Iterator iter) const { return m_pnPosition ==
iter.getPosition(); }
Node* getPosition() { return m_pnPosition; }
Node* getLastNode() { return m_pnLastNode; }
void setPosition(Node* pnNode) { m_pnPosition = pnNode; }
void setLastNode(Node* pnNode) { m_pnLastNode = pnNode; }


// Overloaded Operator
//ostream& operator<<(const Iterator& iter);


private:
// Data Members
Node* m_pnPosition;
Node* m_pnLastNode;
};


// Member Functions
void pushBack(T sString)
{
Node* pnNewNode = new Node(sString);


if (m_pnLastNode == NULL)
{
m_pnLastNode = pnNewNode;
m_pnFirstNode = pnNewNode;
}
else
{
pnNewNode->setPreviousNode(m_pnLastNode);
m_pnLastNode->setNextNode(pnNewNode);
m_pnLastNode = pnNewNode;
}
}


void insert(Iterator iter, T sString)
{
if (iter.getPosition() == NULL)
{
pushBack(sString);
return;
}


Node* pnAfter = iter.getPosition();
Node* pnBefore = pnAfter->getPreviousNode();
Node* pnNewNode = new Node(sString);


pnNewNode->setPreviousNode(pnBefore);
pnNewNode->setNextNode(pnAfter);
pnAfter->setPreviousNode(pnNewNode);


if (pnBefore == NULL)
m_pnFirstNode = pnNewNode;
else
pnBefore->setNextNode(pnNewNode);


}


Iterator erase(Iterator i)
{
Iterator iter = i;
assert(iter.getPosition() != NULL);
Node* pnRemove = iter.getPosition();
Node* pnBefore = pnRemove->getPreviousNode();
Node* pnAfter = pnRemove->getNextNode();


if (pnRemove == m_pnFirstNode)
m_pnFirstNode = pnAfter;
else
pnBefore->setNextNode(pnAfter);


if (pnRemove == m_pnLastNode)
m_pnLastNode = pnBefore;
else
pnAfter->setPreviousNode(pnBefore);


iter.setPosition(pnAfter);
delete pnRemove;


return iter;
}


Iterator begin()
{
Iterator iter;


iter.setPosition(m_pnFirstNode);
iter.setLastNode(m_pnLastNode);


return iter;
}


Iterator end()
{
Iterator iter;


iter.setPosition(NULL);
iter.setLastNode(m_pnLastNode);


return iter;
}


private:
// Data Members
Node* m_pnFirstNode;
Node* m_pnLastNode;



};


#endif
 
R

red floyd

DK said:
I found another thing. If I put all the implementation in the
declaration, it works! So I can't separate declaration and
implementation if I have nested class within a template class??
Umm....weird....

> [redacted]

I'll check it out with VC7.1, but, again, VC6 is known to have loads of
template issues.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top