Solved

Template Class  -  need to resolve an error in the header file

Posted on 2000-04-21
14
168 Views
Last Modified: 2010-04-02
Greetings:

I'm trying to compile the code for a template class as it relates to a List structure.  I'm testing the template header declaration by using one line within main() but I'm getting the following error:

Error stated within VC++:

error LNK2001: unresolved external symbol "public: __thiscall
ListNode<int>::~ListNode<int>(void)" (??1?$ListNode@H@@QAE@XZ)

Error stated within Borlands:

Error MYDEFS.H 23: Invalid use of template 'ListNode<int>' in function
main()

This error occurs on the line which declares the 2nd ListNode() constructor or line 8:

template <class ListData>
class ListNode{

  public:
   // ListNode constructors
   ListNode(){prev = next = NULL;};
   // overloaded constructor
   ListNode(ListNode<ListData> *LN1, // assign value to prev pointer
      ListNode<ListData> *LN2, // assign value to next pointer
      ListData LD)    // assign value to data member
     {prev = LN1; next = LN2; Data = LD;};

   // ListNode destructor
   ~ListNode();

   // get next & previous ListNode pointers
   ListNode<ListData> *GetNextListNode(){return LN->next;};
   ListNode<ListData> *GetPrevListNode(){return LN->prev};

   // set next & previous ListNode pointers
   void SetNextPtr(ListNode<ListData> * LN){next = LN;};
   void SetPrevPtr(ListNode<ListData> * LN){prev = LN;};

   // get ListNode data member
   ListData * GetDataMember(ListNode<ListData> * LN){ return LN->Data;};

   // set ListNode data member
   void SetDataMember(){Data = <ListData>;};


  private:

   ListNode<ListData> *prev;
   ListNode<ListData> *next;
   ListData Data;
};


template <class ListData>
class List{

  public:

   ListNode<ListData> *AddListNode(const ListData &);
   void DeleteList();
   void DeleteListNode(ListNode<ListData> *);
   ListNode<ListData> *GetFirstListNode(){return head;};
   ListNode<ListData> *GetLastListNode(){return tail;};
   List(){head = tail = NULL;}
   ~List();

  private:
   ListNode<ListData> *head;
   ListNode<ListData> *tail;

};


void main()
{

   ListNode<int> LN;

      return;

}

Thanks!



0
Comment
Question by:John500
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 5
14 Comments
 
LVL 5

Expert Comment

by:Wyn
ID: 2738113
->error LNK2001: unresolved external symbol "public: __thiscall
ListNode<int>::~ListNode<int>(void)" (??1?$ListNode@H@@QAE@XZ)
========
This means the implementation of destructor of ListNode is unavailable...
Make sure you have include its library...
Otherwise,you should define it...
0
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2738235
With templates it is common to have to #include it's definition (that is the code!) in all the .cpp files that use them. There are all kinds of strategies but the simplest is to copy the code to the header file that _declares_ the template classes.
0
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2738248
If you have any questionn, let me know
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:John500
ID: 2738396
As stated, I needed to define a destructor for the ListNode class.  I also needed one for the List.  

I recompiled and have no errors using Borland but the following error in VC++:

error C2061: syntax error : identifier 'DeleteList'

This error occurs in the header file within the List class on line:

~List(DeleteList());

Do I need to state the variable type which DeleteList(type) takes as a parameter?

I have only a 'return' statement within main().  Below is the code for the header, ListNode & List destructors:

      template <class ListData>
      class ListNode{

            public:
                  // ListNode constructors
                  ListNode(){prev = next = NULL;};
                  // overloaded constructor
                  ListNode(ListNode<ListData> *LN1,      // assign value to prev pointer
                               ListNode<ListData> *LN2,      // assign value to next pointer
                               ListData * LD)                  // assign value to data member
                              {prev = LN1; next = LN2; Data = LD;};

                  // ListNode destructor
                  ~ListNode();

                  // get next & previous ListNode pointers
                  ListNode<ListData> *GetNextListNode(){return LN->next;};
                  ListNode<ListData> *GetPrevListNode(){return LN->prev;};

                  // set next & previous ListNode pointers
                  void SetNextPtr(ListNode<ListData> * LN){next = LN;};
                  void SetPrevPtr(ListNode<ListData> * LN){prev = LN;};

                  // get ListNode data member
                  ListData * GetDataMember(ListNode<ListData> * LN){ return LN->Data;};

                  // set ListNode data member
                  void SetDataMember(){Data = <ListData>;};


            private:

                  ListNode<ListData> *prev;
                  ListNode<ListData> *next;
                  ListData * Data;
      };


      template <class ListData>
      class List{

            public:

                  ListNode<ListData> *AddListNode(const ListData &);
                  void DeleteList();
                  void DeleteListNode(ListNode<ListData> *);
                  ListNode<ListData> *GetFirstListNode(){return head;};
                  ListNode<ListData> *GetLastListNode(){return tail;};
                  List(){head = tail = NULL;}
                  ~List(DeleteList());

            private:
                  ListNode<ListData> *head;
                  ListNode<ListData> *tail;

      };


// ListNode Destructor
      template <class ListData>
      ListNode<ListData>::~ListNode()
      {

            if(Data)delete Data;
            prev = NULL;
            next = NULL;

      }

// List Destructor
template <class ListData>
      void List<ListData>::DeleteList()
      {
            // create a pointer to the ListNode head
            ListNode<ListData> *CurPtr = head;
            // ListNode pointer used to hold the value of CurPtr
            ListNode<ListData> *temp = NULL;

            while(CurPtr != NULL){
                  // store the pointer of CurPtr
                  temp = CurPtr;
                  // advance CurPtr to next ListNode
                  CurPtr = CurPtr.GetNextListNode();
                  // delete the memory block held by the ListNode
                  delete(GetDataMember(temp));
                  // delete current ListNode
                  delete(temp);
            }
            head = NULL;
            tail = NULL;
            return;
      }


0
 

Author Comment

by:John500
ID: 2738425
Scratch the question about including the 'type' for DeleteList().  I was thinking about a similar function I have which deletes ListNodes not Lists:

template <class ListData>
      void List<ListData>::DeleteListNode(ListNode<ListData> *NodPtr)


....
0
 
LVL 7

Accepted Solution

by:
KangaRoo earned 50 total points
ID: 2738733
Is this an exact copy past of your code?

>> void SetDataMember(){Data = <ListData>;};

And

>> ~List(DeleteList());

Destructor can not take arguments
0
 

Author Comment

by:John500
ID: 2739032
KangaRoo,

Yes, the line below is an exact copy.

>> void SetDataMember(){Data = <ListData>;};

I guess one thing wrong here is that I need the pointer:

<ListData> *

0
 

Author Comment

by:John500
ID: 2739068
KangaRoo,

What do you think about this:

SetDataMember(<ListData> *LN){Data = LN;};
0
 

Author Comment

by:John500
ID: 2739115
Ok, I made the following changes and things seem to be Ok.  Anything else stand out as bad?

void SetDataMember(ListData *LN){Data = LN;};

~List(){DeleteList();};


0
 

Author Comment

by:John500
ID: 2739139
KangaRoo,

Thanks for the two pointers.  

Now that I'm running the code in main() I'm having a problem on the line that goes:

*LNPtr1 = LNb;

When I say trouble I mean the program crashes "Unhandled exception.  Access Violation"

Here is the whole thing.

void main()
      {

             ListNode<Owner> LNa;
             ListNode<Owner> LNb;
             ListNode<Owner> *LNPtr1 = NULL;

             LNa.SetNextPtr(LNPtr1); // set next to NULL.

             ListNode<Owner> *LNPtr2 = LNa.GetNextListNode(); // Check that it gets NULL.

             *LNPtr1 = LNb;
             LNa.SetNextPtr(LNPtr1); // set next to LNb
             LNPtr2 = LNa.GetNextListNode(); // Check that it points to LBb.

             return;

      }
0
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2739475
>> ListNode<Owner> *LNPtr1 = NULL;
>> [....]
>> *LNPtr1 = LNb;

The first statement initializes a ListNode* to NULL, iow, it is pointing at nothing. It is not uncommon to do so, a null pointer is shouting out "Don't derefence me!". Which is exactly what is happening in the second statement.  And since this is not an uncommon error, the OS has protected that area.

Note that you are want to assign one node to another. Since you've not defined operator=(), the compiler will make one that simply copies all data members. Now one of the datamembers is a pointer to am object, that will now be shared by two nodes, and both will eventually try to 'delete' that object. Ouch.
0
 

Author Comment

by:John500
ID: 2739820
Ok, so all is well, except that my test was not a valid test, right?
0
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2740043
I'd have to investigate the code, until now we were looking to get it compiled.
0
 

Author Comment

by:John500
ID: 2740447
Ok, how about I open another question but I'm now more concerned with declaring a 'List' variable within main()
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
C++ get user from AD  (VS6) 7 97
PDF library for Delphi 2 135
C++ Code Issue 4 38
Adding items to a C# list incrementally 5 64
When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question