Link to home
Start Free TrialLog in
Avatar of John500
John500Flag for United States of America

asked on

Template Class - Need to write a procedure that will print out info after comparing multiple index (tree) data

Greetings:

This question has two parts.  If the answers aren't resolved easily, I'll increase the points as necessary.

Before I give the details of the second part, I need to know why I get the following error when I call a template class member function within main():

error C2065: 'ReadOutputFile' : undeclared identifier

Here is the class definition:

template <class ListData>
      class DBOutput
      {

            public:

                  void PrintOwners(IndexNode<ListData> *);
                  void ReadOutputFile();



            private:

                  List<ListData>  List;
                  Index<ListData> SSNIndex;
                  Index<ListData> GSNIndex;
                  Index<ListData> SSN_GSNIndex;
      };

Here is the ReadOuptFile() procedure:

template <class ListData>
      void DBOutput<ListData>::ReadOutputFile()
      {
            
            PrintOwners(SSN_GSNIndex.GetRoot());

      }

I'll post any other code when necessary.  Thanks






Avatar of KangaRoo
KangaRoo

Remarkable, there seems nothing wrong with the code snippet.

Undeclared identifiers could also be caused by incorrect (declaration) statements preceding the declaration of the function.
Where is the function implementation for ReadOutputFile?  It should be in the header file, and not in a separate .cpp file.
Is your definition of your template class in the same H file as its declaration or is it in a separate CPP file ? I have seem strange behaviors when they are in separate files, and everything works fine if they are in one single H file.
Avatar of John500

ASKER

JoeDol,

What I usually do is define long(er) functions in the .cpp file.  If they are short & sweet, I define them in the header file.

All my code is presently this way for numerous functions.  I can't see why it would be choking on this one.  

Are you saying I should define the ReadOutputFile() in the header file.  Thus, under my 'public' declarations I would give the full functions definition?

I hate to do it that way, but I'll try it just for experience sake.
I know. I don't like to do that too, but it's the only safe way with template and how compilers (VC at least) actually handle them. I have had problems in the past for this reason. But I can't remember if the error was an 'Undeclared identifier'. You don't have to include that in your class declaration. You can also inline the method definition after your class declaration.
Avatar of John500

ASKER

JoeDol,

I modified the header file to look like this:

template <class ListData>
      class DBOutput
      {

            public:

                  void PrintOwners(IndexNode<ListData> *);
                  void ReadOutputFile(){PrintOwners(SSN_GSNIndex.GetRoot());};

            private:

                  List<ListData>  List;
                  Index<ListData> SSNIndex;
                  Index<ListData> GSNIndex;
                  Index<ListData> SSN_GSNIndex;
      };

When I use the in-line method for ReadOutputFile(), it's no big deal right now because there isn't much code in it.  But after I get more code, are you saying I can put this function somewhere else in the header file, like after the class definition?

However, strangely enough, using the in-line method didn't resolve my problem.  What's more amusing is that in the process of reviewing the code, I notice that the other function I call in main (I only have two right now) was not defined properly in the .ccp file.  I had forgot the prefix 'OwnerDB::', when I added it, I ended up getting two errors for main:

void main()
      {
            
            ReadOwnerFile();            

            ReadOutputFile();

            return;

      }

error C2065: 'ReadOwnerFile' : undeclared identifier
error C2065: 'ReadOutputFile' : undeclared identifier

I was able to compile and run the code without a proper definition before I added the ReadOutputFile() procedure???

Could you send a complete copy of your code both the cpp for main and your h file with your template ?
ReadOutputFile is a method of your template class, isnt'it ? But in your main you call it like a global function... am i missing something ?
Avatar of John500

ASKER

JoeDol,

This is about my second attempt using templates.  When you say I'm calling the procedure as a global function, how else should I be calling it, or what would be proper?
Then VC messes up the error messages. The template definitions should be included in every translation unit with most compilers. Failure to do so would lead to `undefined symbol' errors from the linker, not to `undeclared ...' from the compiler.
Avatar of John500

ASKER

Ok, I guess I needed something like this:

void main()
      {
            

            DBOutput<Owner> Report1;
            OwnerDB Owners;            
      
            Owners.ReadOwnerFile();            

            Report1.ReadOutputFile();

            return;

      }

Let me know if you want to help with the procedure I need to write.
Is the problem solved? If so you can award points. It's not that I wouldn't want to help any further, bit it's clearer for everyone if different question reside in different threads. Besides, a new question will get attention from more experts.
Avatar of John500

ASKER

I'll give JoeDol some more time to decide if he wants to continue this.  If not, I'll have to close it out.  My last comment was in response to his point about my function calls being global.
may be i don't understand something, but next code minimum translated:

class  OwnerDB
{
  public:
   void ReadOwnerFile(void);
   OwnerDB *GetRoot(void);
};
template <class ListData>
class DBOutput
{
  public:
   void PrintOwners(ListData *);
   void ReadOutputFile();
  private:
   ListData  List;
   ListData SSNIndex;
   ListData GSNIndex;
   ListData SSN_GSNIndex;
};

template <class ListData>
void DBOutput<ListData>::ReadOutputFile()
{
   PrintOwners(SSN_GSNIndex.GetRoot());
}

void main()
{
  DBOutput<OwnerDB> Report1;
  OwnerDB Owners;

  Owners.ReadOwnerFile();

  Report1.ReadOutputFile();
}
Avatar of John500

ASKER

AlexVirochovsky,

It looks like your code was close.  The two variables (Report1, Owners) needed a little more.  How about I close this question out and except your answer after it compiles?

The code would compile in main() until I included this line:

Report1.ReadOutputFile();

I received the following error for its member function 'PrintOwners()':

error C2440: '=' : cannot convert from 'class ListNode<class OwnerDB<class Owner> > *' to 'class ListNode<class Owner> *'

Here is the code.  I also included the 'Index' class code because it is the class that actually has the 'GetRoot()' member function.  You had it in a different class.  Got any ideas how I can modify the PrintOwner() function to make this work?



void main()
      {

        DBOutput<OwnerDB<Owner> > Report1;
        OwnerDB<Owner> Owners;

        Owners.ReadOwnerFile();

        Report1.ReadOutputFile();

      }



      template <class ListData>
      void DBOutput<ListData>::PrintOwners(IndexNode<ListData> *IndNodPtr)
      {
            
            string Output;
            ListNode<Owner>  *LstNod;
            
            if(!IndNodPtr)
                  return;

            LstNod = IndNodPtr->GetListNode();

            PrintOwners(IndNodPtr->GetRightPtr());      // traverse right subtree

                  Output = LstNod->GetData().GetLast()     + "," +
                               LstNod->GetData().GetSSN()      + "," +  
                               LstNod->GetData().GetGunManuf() + "," +  
                               LstNod->GetData().GetGunSN()    + "\n";
                  
                  WriteToLog(Output);
            
            PrintOwners(IndNodPtr->GetLeftPtr());                  // traverse right subtree
            return;
      }

      template <class ListData>
      class Index{

            public:

                  // Index constructor      
                  Index(){Root = NULL;};

                  // Index destructor
                  ~Index(){DeleteIndex();};

            
                  void AddIndex(string, ListNode<ListData> *);      // add node to index                  
                  void DeleteIndex();                                                // delete the entire index                  
                  void DeleteIndexNode(IndexNode<ListData> *,       // delete one index node                  
                                                 string);
                  IndexNode<ListData> *GetRoot(){return Root;};      // get root

                  ListNode<ListData> *SearchIndexNode(string);      // get ListNode member                   

                  IndexNode<ListData> *SearchIndex(string);            // get IndexNode


            private:

                  // set tree node pointers after deleting a tree node
                  void HookIndexNode( IndexNode<ListData> *,      // child
                                                IndexNode<ListData> *,      // parent
                                                IndexNode<ListData> *);      // current pointer

            private:

                  IndexNode<ListData> *Root;
      };
Avatar of John500

ASKER

AlexVirochovsky,

Although it may be obvious, I forgot to mention that the error appears on the following line within the PrintOwners() function:

LstNod = IndNodPtr->GetListNode();
You code (without errors):

void WriteToLog(std::string Output)
{
}
class  Owner
{
  public:
  Owner GetData();
  std::string GetLast();
  std::string GetSSN();
  std::string GetGunSN();
  std::string GetGunManuf();
};

class  OwnerDB
{
  public:
   void ReadOwnerFile(void);
   OwnerDB *GetRoot(void);
   Owner *GetListNode();
   OwnerDB *GetRightPtr();
   OwnerDB *GetLeftPtr();
};
template <class ListData>
class DBOutput
{
  public:
   void PrintOwners(ListData *);
   void ReadOutputFile();
  private:
   ListData  List;
   ListData SSNIndex;
   ListData GSNIndex;
   ListData SSN_GSNIndex;
};
template <class ListData>
void DBOutput<ListData>::ReadOutputFile()
{
   PrintOwners(SSN_GSNIndex.GetRoot());
}


template <class ListData>
void DBOutput<ListData>::PrintOwners(ListData *IndNodPtr)
{
  std::string Output;
  Owner  *LstNod;

  if(!IndNodPtr)
   return;

  LstNod = IndNodPtr->GetListNode();

  PrintOwners(IndNodPtr->GetRightPtr()); // traverse right subtree

  Output = LstNod->GetData().GetLast()     + "," +
  LstNod->GetData().GetSSN()      + "," +
  LstNod->GetData().GetGunManuf() + "," +
  LstNod->GetData().GetGunSN()    + "\n";

  ::WriteToLog(Output);

  PrintOwners(IndNodPtr->GetLeftPtr()); // traverse right subtree
  return;
}

template <class ListData> class Index{

public:
  // Index constructor
  Index(){Root = NULL;};

// Index destructor
 ~Index(){DeleteIndex();};


 void AddIndex(std::string, ListData *); // add node to index
void DeleteIndex(); // delete the entire index
void DeleteIndexNode(ListData *, std::string);// delete one index node

ListData *GetRoot(){return Root;}; // get root

ListData *SearchIndexNode(std::string); // get ListNode member

ListData *SearchIndex(std::string); // get IndexNode


private:

// set tree node pointers after deleting a tree node
void HookIndexNode( ListData *, // child
ListData *, ListData *); // current pointer

private:

ListData *Root;
};

void main()
{
  DBOutput< OwnerDB> Report1;
  OwnerDB Owners;

  Owners.ReadOwnerFile();

  Report1.ReadOutputFile();

}
Tested with Bc 5.01
Alex
BTW: i hope, i can answer after 1 hour
translation you code.
Avatar of John500

ASKER

AlexVirochovsky,

Notice below you have the 'Get' functions within the 'OwnerDB' class.  I have them in either the 'List' or 'Index' class:


You Wrote:

class  OwnerDB
{
  public:
   void ReadOwnerFile(void);
   OwnerDB *GetRoot(void);
   Owner *GetListNode();
   OwnerDB *GetRightPtr();
   OwnerDB *GetLeftPtr();
};


My Definitions:

template <class ListData>
      class ListNode{

            public:
                  // get next & previous ListNode pointers
                  ListNode<ListData> *GetNextPtr(){return next;};
                  ListNode<ListData> *GetPrevPtr(){return prev;};

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

                  // set ListNode data member
                  void SetData(ListData *LN){Data = LN;};

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

      template <class ListData>
      class Index{

            public:

                  void AddIndex(string, ListNode<ListData> *);      // add node to index
                  void DeleteIndex();                                                // delete the entire index
                  void DeleteIndexNode(string);                               // delete one index node

                  IndexNode<ListData> *GetRoot(){return Root;};      // get root
                  ListNode<ListData> *SearchIndexNode(string);      // get ListNode member
                  IndexNode<ListData> *SearchIndex(string);            // get IndexNode

            private:

                  IndexNode<ListData> *Root;
      };

Are you saying it is necessary to have the 'Get' functions in the OwnerDB class or is there a way to modify the DBOutput class?

ASKER CERTIFIED SOLUTION
Avatar of AlexVirochovsky
AlexVirochovsky

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial