Solved

attempting to convert a single-file project into a multi-file class-based project.

Posted on 2011-09-07
10
454 Views
Last Modified: 2013-12-14
Im attempting to adapt the solution from here for my own purposes but am having issues breaking it down into a mult-file class (.h &.cpp)
Attached are the main.cpp Dicto.cpp and Dicto.h files as I have them currently (will not compile)

Upon compiling I get errors dealing with the Dicto pointer "root" stating it is undeclared though I have it declared in the header and initialized in the constructor.

Please advise I'm sure there is something simple that I've overlooked.
#include <iostream>
#include <fstream>
#include <string>
#include "functions.h"
#include "Dicto.h"
using namespace std;
Dictio::Dictio()
{
   root = new Dictio;
   for (int i = 0; i < 26; ++i)
      a[i] = 0;
   FlagEndWord = false;
   
}

Dictio::~Dictio()
{
   for (int i = 0; i < 26; ++i)
      delete a[i];
}
bool VerifyWord(const char * word, int len)
{
   int plen;
   Dictio * n = root->follow(word,len,plen);
   return (plen == len && n -> IsFullWord());
}

// insert the word into dictionary.
void Dictio::InsertDictionary(const char * word, int len)
{
   int plen;
   Dictio * n = root -> follow(word,len,plen);
   if (plen == len) {
      n -> FlagEndWord = true;
      return;
   }
   // need to add more nodes to the tree.
   do {
      char c = word[plen++];
      if (c >= 'A' && c <= 'Z')
        c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // Not a word letter.
         // Now if you want to allow for - or other
         // letters in words you can always arrange for
         // that by allow for 27 or more letters in that
         // array, but then the waste becomes even more
         // appearant as every node will have those extra
         // pointers.
         // throw some error if you want here.
         return;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next != 0) {
         // follow() didn't do what it's supposed to do.
         // fatal error, throw error or something if you
         // want here.
         return;
      }
      next = n = new Dictio;
   } while (plen < len);
}

// read the file and add words to dictionary.
void AppendDictionary(const char * file)
{
   ifstream f(file);
   char buf[100];

   // each line is one word.
   while (f.getline(buf,sizeof(buf),'\n')) {
      // skip the newline at end of line if any.
      f.ignore(1024,'\n');
      Dictio::InsertDictionary(buf,strlen(buf));
   }
}

Dictio * Dictio::follow(const char * word, int len, int & plen)
{
   int x = 0;

   Dictio * n = this;
   while (x < len) {
      char c = word[x++];
      if (c >= 'A' && c <= 'Z')
         c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // again not a legal letter....
         break;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next == 0) {
         // continuation not in dictionary.
         break;
      }
      n = next;
   }
   plen = x;
   return n;
}

Open in new window

// reading a text file
#include <iostream>
#include <fstream>
#include <string>
#include "functions.h"
#include "Dicto.h"
using namespace std;


Dictio * root = new Dictio;



int main()
{
   AppendDictionary("dict.txt");
   // use it as you like.
   // if you have a word in a buffer and the length of it
   // you can check if it is in the dictionary by calling
   // follow or VerifyWord.
}

Open in new window

class Dictio {
private:
  Dictio * a[26];
  bool FlagEndWord;
  Dictio * root;
  

public:
   Dictio();
   ~Dictio();
   
   // This function follow from the current node
   // the letters given by word. The word is assumed
   // to be len characters.
   // On output plen will have the length of characters
   // leading to the returned entry.
   // The function searches from the given node
   // for a continuation using the first letter of
   // word and so on until it either find a complete
   // plen == len on output it means the whole word
   // has been read to reach the returned node, otherwise
   // the search stopped at some node because there is
   // no continuation present for the given leters.
   // len == plen and returned node has FlagEndWord
   // it means the input word was in the dictionary and
   // is a complete word.
   // if len == plen but the returned node do not have
   // FlagEndWord it means the 'word' contains a valid
   // prefix but is not in itself a complete word.
   // iF plen < len then not all the characters in word
   // could be followed because the word is not in the
   // dictionary, the plen indicate how many letters make
   // up a prefix that IS in the dictionary.
   // The functions VerifyWord and VerifyList can easily
   // be implemented in terms of this function.
   // also, insertion into the dictionary can be made
   // using this function as this function return the
   // leaf node that represent a prefix.

   Dictio * follow(const char * word, // the word
                   int len, // length of word
                   int & plen); // OUT: Length of prefix.

   bool IsFullWord() const { return FlagEndWord; }

   static void InsertDictionary(const char * word, int len);
};

Open in new window

0
Comment
Question by:ExMachina1123
  • 6
  • 3
10 Comments
 

Author Comment

by:ExMachina1123
ID: 36499228
increased points
0
 
LVL 24

Accepted Solution

by:
alexey_gusev earned 500 total points
ID: 36500877
in VerifyWord() you're using "root" which is declared in main file, so it's not visible in that function. add

extern Dictio* root;

somewhere before VerifyWord().

and besides, shouldn't VerifyWord be a member of Dictio class ?
0
 

Author Comment

by:ExMachina1123
ID: 36500936
ok I changed the .h file to the following

class Dictio {
private:
  Dictio * a[26];
  bool FlagEndWord;
  Dictio * root;
  

public:
   Dictio();
   ~Dictio();

   bool VerifyWord(const char * word, int len);
   void Dictio::AppendDictionary(const char * file);
   Dictio * follow(const char * word, // the word
                   int len, // length of word
                   int & plen); // OUT: Length of prefix.

   bool IsFullWord() const { return FlagEndWord; }

   static void InsertDictionary(const char * word, int len);
};

Open in new window

and the .cpp to
#include <iostream>
#include <fstream>
#include <string>
#include "functions.h"
#include "Dicto.h"
using namespace std;

extern Dictio* root;

Dictio::Dictio()
{
  // root = new Dictio;
   for (int i = 0; i < 26; ++i)
      a[i] = 0;
   FlagEndWord = false;
   
}

Dictio::~Dictio()
{
   for (int i = 0; i < 26; ++i)
      delete a[i];
}

bool Dictio::VerifyWord(const char * word, int len)
{
   int plen;
   Dictio * n = root->follow(word,len,plen);
   return (plen == len && n -> IsFullWord());
}

// insert the word into dictionary.
void Dictio::InsertDictionary(const char * word, int len)
{
   int plen;
   Dictio * n = root -> follow(word,len,plen);
   if (plen == len) {
      n -> FlagEndWord = true;
      return;
   }
   // need to add more nodes to the tree.
   do {
      char c = word[plen++];
      if (c >= 'A' && c <= 'Z')
        c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // Not a word letter.
         // Now if you want to allow for - or other
         // letters in words you can always arrange for
         // that by allow for 27 or more letters in that
         // array, but then the waste becomes even more
         // appearant as every node will have those extra
         // pointers.
         // throw some error if you want here.
         return;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next != 0) { 
         // follow() didn't do what it's supposed to do.
         // fatal error, throw error or something if you
         // want here.
         return;
      }
      next = n = new Dictio;
   } while (plen < len);
}

// read the file and add words to dictionary.
void Dictio::AppendDictionary(const char * file)
{
   ifstream f(file);
   char buf[100];

   // each line is one word.
   while (f.getline(buf,sizeof(buf),'\n')) {
      // skip the newline at end of line if any.
      f.ignore(1024,'\n');
      Dictio::InsertDictionary(buf,strlen(buf));
   }
}

Dictio * Dictio::follow(const char * word, int len, int & plen)
{
   int x = 0;

   Dictio * n = this;
   while (x < len) {
      char c = word[x++];
      if (c >= 'A' && c <= 'Z')
         c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // again not a legal letter....
         break;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next == 0) {
         // continuation not in dictionary.
         break;
      }
      n = next;
   }
   plen = x;
   return n;
}

Open in new window


but I am getting error
Error      1      error C2227: left of '->follow' must point to class/struct/union/generic type      
targeting the line

Dictio * n = root -> follow(word,len,plen);

Open in new window


we are getting closer.


0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 86

Expert Comment

by:jkr
ID: 36503363
Try removing the whitespace about the operator, i.e.
Dictio * n = root->follow(word,len,plen);

Open in new window

0
 
LVL 24

Assisted Solution

by:alexey_gusev
alexey_gusev earned 500 total points
ID: 36506371
indeed, we are getting closer :)

so, I feel I have to clarify few things:

- if you declared some member variable then it is visible in any member functions EXCEPT static ones (eg InsertDictionary() in your last post)
- static functions and members are like global ones but provide more OO design and so on
- you can declare global variables in one file and then use "extern sometype somevariable" in other files so it's visible there OR put that line in header file and include it; but you have to declare the variable itself somewhere, so compiler knows how to compile and link the code

So to cut long story short, your InsertDictionary is static, so root variable does NOT exist for such case (because it is not declared as "static"). I'm not sure why InsertDictionary() should ever be static. So I'd advise to spend some time on cleaning up the design issues.
0
 

Author Comment

by:ExMachina1123
ID: 36507302
removing white space had no effect.
0
 

Author Comment

by:ExMachina1123
ID: 36507326
removing "static" allowed compilation!
0
 

Author Comment

by:ExMachina1123
ID: 36507334
for any one with future interest the following will compile

main. cpp
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
#include "functions.h"
#include "Dicto.h"
using namespace std;

Dictio * test = new Dictio;

int main()
{
   test->AppendDictionary("dict.txt");
   // use it as you like.
   // if you have a word in a buffer and the length of it
   // you can check if it is in the dictionary by calling
   // follow or VerifyWord.
}

Open in new window


Dicto.h
class Dictio {
private:
  Dictio * a[26];
  bool FlagEndWord;
  Dictio * root;
  

public:
   Dictio();
   ~Dictio();

   bool VerifyWord(const char * word, int len);
   void AppendDictionary(const char * file);
   Dictio * follow(const char * word, // the word
                   int len, // length of word
                   int & plen); // OUT: Length of prefix.

   bool IsFullWord() const { return FlagEndWord; }

   void InsertDictionary(const char * word, int len);
};

Open in new window


Dicto.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "functions.h"
#include "Dicto.h"
using namespace std;

extern Dictio* root;

Dictio::Dictio()
{
  // root = new Dictio;
   for (int i = 0; i < 26; ++i)
      a[i] = 0;
   FlagEndWord = false;
   
}

Dictio::~Dictio()
{
   for (int i = 0; i < 26; ++i)
      delete a[i];
}

bool Dictio::VerifyWord(const char * word, int len)
{
   int plen;
   Dictio * n = root->follow(word,len,plen);
   return (plen == len && n -> IsFullWord());
}

// insert the word into dictionary.
void Dictio::InsertDictionary(const char * word, int len)
{
   int plen;
   Dictio * n = root->follow(word,len,plen);
   if (plen == len) {
      n -> FlagEndWord = true;
      return;
   }
   // need to add more nodes to the tree.
   do {
      char c = word[plen++];
      if (c >= 'A' && c <= 'Z')
        c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // Not a word letter.
         // Now if you want to allow for - or other
         // letters in words you can always arrange for
         // that by allow for 27 or more letters in that
         // array, but then the waste becomes even more
         // appearant as every node will have those extra
         // pointers.
         // throw some error if you want here.
         return;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next != 0) { 
         // follow() didn't do what it's supposed to do.
         // fatal error, throw error or something if you
         // want here.
         return;
      }
      next = n = new Dictio;
   } while (plen < len);
}

// read the file and add words to dictionary.
void Dictio::AppendDictionary(const char * file)
{
   ifstream f(file);
   char buf[100];

   // each line is one word.
   while (f.getline(buf,sizeof(buf),'\n')) {
      // skip the newline at end of line if any.
      f.ignore(1024,'\n');
      Dictio::InsertDictionary(buf,strlen(buf));
   }
}

Dictio * Dictio::follow(const char * word, int len, int & plen)
{
   int x = 0;

   Dictio * n = this;
   while (x < len) {
      char c = word[x++];
      if (c >= 'A' && c <= 'Z')
         c = c - 'A' + 'a';
      if (c < 'a' || c > 'z') {
         // again not a legal letter....
         break;
      }
      Dictio * & next = n -> a[c - 'a'];
      if (next == 0) {
         // continuation not in dictionary.
         break;
      }
      n = next;
   }
   plen = x;
   return n;
}

Open in new window


thanks alot alexy!
0
 

Author Closing Comment

by:ExMachina1123
ID: 36507344
thanks again!
0
 
LVL 24

Expert Comment

by:alexey_gusev
ID: 36507986
just for the sake of education :) - if I were you, I'd pass Dictio* to InsertDictionary() instead of using global variable "root" in 2 files
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

825 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