473,387 Members | 1,493 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Nested Class Template

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

Oct 20 '05 #1
11 3560
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;
}
}

Oct 20 '05 #2
cy*******@sbcglobal.net wrote:
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-lit...html#faq-35.12
Oct 20 '05 #3
In article <gm****************@newssvr29.news.prodigy.net>,
red floyd <no*****@here.dude> wrote:
cy*******@sbcglobal.net wrote:
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-lit...html#faq-35.12


And http://www.comeaucomputing.com/techt.../#whylinkerror
--
Greg Comeau / Celebrating 20 years of Comeauity!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Oct 20 '05 #4
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;
....

};

Oct 20 '05 #5
DK wrote:
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.
Oct 20 '05 #6
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

Oct 20 '05 #7
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

Oct 20 '05 #8
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

Oct 20 '05 #9
DK wrote:
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.
Oct 20 '05 #10
DK
red floyd: thanks! let me know if you find anything =)

DK

Oct 20 '05 #11
DK wrote:
red floyd: thanks! let me know if you find anything =)

DK


Comeau online liked it (once I removed the line of '******'s )
Oct 21 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: CoolPint | last post by:
I read in books that nested class cannot access private members of nesting class and vice versa unless they are made friends. Somehow, my compiler is letting my nested class member functions access...
3
by: Ike Naar | last post by:
Given the following C++ snippet: template < typename T > class A { // 1 public : // 2 class AA { } ; // 3 } ; ...
1
by: Chris Schadl | last post by:
Okay, I'm having a bit of a brain-fart and I can't remember how I would do this. Say I have the following: template <typename T1, typename T2> class A; // Forward declaration of A template...
2
by: Dominik Fritz | last post by:
Hi, I have a template class which contains a nested class. The .cpp file is included at the end of the header file. If I write the implementation of a member function of my nested class in this...
4
by: Mr Dyl | last post by:
I'm trying to declare the following friendship and VS.Net 2003 is complaining: template <class T> class Outter { class Inner {...} ... }
4
by: bigbarn | last post by:
Hi - I can't seem to figure this one out, help is appreciated: Header file: template <class T> class Foo { T val; }; template<class T> class Bar {
4
by: rach | last post by:
I just started to learn C++. I copied the following code from a data structure textbook to a ".h" file and couldn't compile it. The code contains three template interfaces. One inherits another. The...
3
by: jdurancomas | last post by:
Dear all, I'm trying to declare the operator++ to a nested class. The nested class is not template but the container it is. The code used in teh sample program is included bellow: ...
5
by: huili80 | last post by:
For example, like in the following, the part commented out was intended as partial spectialzation, but it would even compile. Is it even legal to partially specialize a nested template class...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.