Help in my program using Classes

  • Thread starter Thread starter yungman
  • Start date Start date
  • Tags Tags
    Classes Program
Click For Summary
The discussion revolves around troubleshooting a C++ program that integrates classes for managing a directory of names and their associated contact information. The user faced an error related to member function calls, specifically regarding the use of parentheses for static and instance methods. Clarifications were provided on how to correctly call these functions and the importance of understanding the distinction between static and instance methods.The user also encountered issues with file handling, particularly when writing data from a vector to a file, which led to a "vector subscript out of range" error. Suggestions were made to simplify the writing process by using a single call to write the entire vector at once, rather than looping through each element. Additionally, it was advised to declare variables close to their usage and to avoid unnecessary member variables, promoting cleaner and more efficient code.Overall, the conversation highlighted the importance of understanding C++ class structures, proper function usage, and effective file management practices, while also encouraging a more streamlined coding approach to enhance readability and maintainability.
  • #31
Jarvis323 said:
Can it be that you didn't save the file after making the changes until you closed VS? Another possibility is that VS is somehow not tracking changes to the header file. Build systems track if a file has changed and only rebuild a cpp file if necessary. I've had issues before in other build systems where it didn't detect the change to a header file and then didn't actually rebuild it until I force it to. I doubt VS would have that problem, but not sure.
I always have a habit to save the stuffs every time I change something. Particularly it was very late last night about 2am, I just copy and pasted the 3 files to and new program and went to bed. I ran the new program when I got up this morning, it ran to the writeFile, so I opened the original program and it ran also.

I don't even care at this point, just count it as my fault. I am too busy working on the program as I am very close to the finishing line.

Also, I notice VS is very good telling me what's wrong in smaller programs, with this program, I can make very obvious error in the header files and VS won't show the red wiggle line below the code like it normally does. But what do I know...
 
Technology news on Phys.org
  • #32
yungman said:
I am pushing myself to very uncomfortable area. I cannot say enough how much I learn writing this program. I don't think I would learn nearly as much if I take the easy way and just work through the programs in the book and cover more chapters.
Personally, I wish you would stop pushing yourself so far beyond your current knowledge. The only reason you are able to learn as much as you have, is not because of your persistence in bulling through stuff you don't know about, but is instead because of the patience of the people who respond in your threads. Frankly, some of the people who have helped in the past have gotten fed up, and have decided against helping you further.
 
  • Like
Likes Vanadium 50
  • #33
yungman said:
Also, I notice VS is very good telling me what's wrong in smaller programs, with this program, I can make very obvious error in the header files and VS won't show the red wiggle line below the code like it normally does.
But it shows you a list of errors, such as one you asked about earlier in this thread, C3867.

Here's a link to the page in the VS docs where this compile error is discussed: https://docs.microsoft.com/en-us/cp...r-errors-2/compiler-error-c3867?view=msvc-160

Try as I might, I don't find any Russian on this page (I speak some Russian). It's all in English, together with an example of some code that throws this error and advice on how to fix the problem.
 
  • Like
Likes Vanadium 50
  • #34
yungman said:
Yes, I agree. I gave a lot of thought about this. Yes, I did it the first time smoothly with just one header file a while back already, I manage to store in file and read back...That's the reason I decided to use two header files!

I guess I am into S&M! :biggrin: ?:)o_O.....No seriously, I know people use multiple Classes, so I might as well start now. I am pushing myself to very uncomfortable area. I cannot say enough how much I learn writing this program. I don't think I would learn nearly as much if I take the easy way and just work through the programs in the book and cover more chapters. I decided to throw my schedule out the window and just get to it when I am ready. I have been working on this program 8+ hours a day, 7 days a week. I determine to complete this program. I am very close! Hopefully this is the last step, saving to the file. Everything else is working already.

thanks for your concern.
I think the main issue is that the organization isn't very good.

What I might do if I want to break it up like you are doing into multiple classes, is to create a DirectoryIO class that deals with IO. IO includes user input, reading and writing. Then I would have a Directory (managing the collection of DirectoryEntries) class, and it would also have a DirectoryIO object. Then your main function would have not much in it. Something like this.

C:
DirectoryEntry
     name
     address

//doesn't hold any data only takes the data as arguments
DirectoryIO
    writeDirectoryEntry(
        const string & filePath,
        const Directory & d );
    writeDirectories(
        const string & filePath,
        const vector<DirectoryEntrie> & directories );
    inputDirectory(); // get user input
    read(...

Directory
    vector<DirectoryEntry> entries;
    DirectoryIO IOManager;
    addEntry(...)
    ...

There is a whole lot to learn on organization and design. A popular design pattern is the component/composition design pattern.

https://www.learncpp.com/cpp-tutorial/102-composition/
 
Last edited:
  • #35
Jarvis323 said:
I think the main issue is that the organization isn't very good.

What I might do if I want to break it up like you are doing into multiple classes, is to create a DirectoryIO class that deals with IO. IO includes user input, reading and writing. Then I would have a Directory (managing the collection of DirectoryEntries) class, and it would also have a DirectoryIO object. Then your main function would have not much in it. Something like this.

C:
DirectoryEntry
     name
     address

//doesn't hold any data only takes the data as arguments
DirectoryIO
    writeDirectoryEntry(
        const string & filePath,
        const Directory & d );
    writeDirectories(
        const string & filePath,
        const vector<DirectoryEntrie> & directories );
    inputDirectory(); // get user input
    read(...

Directory
    vector<DirectoryEntry> entries;
    DirectoryIO IOManager;
    addEntry(...)
    ...

There is a whole lot to learn on organization and design. A popular design pattern is the component/composition design pattern.

https://www.learncpp.com/cpp-tutorial/102-composition/
Hi Jarvis323

Thanks for the advice, it's a little late to change direction at this point as I think if I can fix the problem of DirV[] to the fileManage, the program should work. I know if I put file handling into vectorEdit.h, it should work with no problem.

I simplified the program to a few lines, I think the problem is the header files must have a different way of communicate. Obviously main() has no problem communicating with either header file to do things, but not between the two header files. Here is the short program:

main():
C++:
#include <iostream>
#include <cstring>
#include <vector>
#include "fileManage.h"
#include "vectorEdit.h"
using namespace std;
vectorClass vectC;
fileClass file;
int main()
{ cout << " Enter the last name: "; cin >> vectC.Dir.lastName;
  cout << endl;
  vectC.printName();
  file.goPrint();
  vectC.printName();
  return 0;
}//End main()

Here is the vectorEdit.h
C++:
#ifndef vectorEdit_H
#define vectorEdit_H
#include <vector>
#include <fstream>
#include <iomanip>
#include <iostream>

class vectorClass
{
  private:
    const static int nameLen = 25, phoneLen = 12;
  public:
    struct Directory
    {   char lastName[nameLen]; char firstName[nameLen];
        char phone[phoneLen]; int element;
    };
    Directory  Dir;
    void printName()
    { std::cout << " In vectorEdit, name is: " << Dir.lastName << "\n\n"; }

};
#endif

Here is the fileManage.h
C++:
#ifndef fileManage_H
#define fileManage_H
#include <vector>
#include <fstream>
#include <iostream>
#include "vectorEdit.h"
//using namespace std;

class fileClass
{    public:
        vectorClass vectC;
        bool newF, failOpen;
        std::fstream file;

        void goPrint() { std::cout << " In fileManage  " <<
            vectC.Dir.lastName << "\n\n"; vectC.printName(); }
};//End of fileClass
#endif

Here is the screen capture of the cmd:
output.jpg


1) main() calling member function printName() in vectorEdit.h. It works.
2) main() calling member function goPrint() in filemanage.h, it will NOT print "name is: Alan".
3) also in goPrint() it calls call printName() in vectorEdit.h Notice even calling the same printName(), it missed "Alan"
4) to confirm Dir still contain "Alan", main() call printName() one last time and it shows everything is there.Bottom line, fileManage.h cannot do anything on the data.

Am I just missing a little bit or it'll take a lot more to make this work. Obvious if it takes a lot more, I will just put the file handling back in vectorEdit.h, it's proven it will work as long as they are in the same header file. It is very clear this is way over my head.

Thanks for the advice.
 
  • #36
You have two vectorsClass objects, one in main, and another in the file object. They're different objects and an operation on one of them doesn't affect the other.

So you have to do something like remove the one in the file class, and pass in the one from main as an argument to the print function. Or delete the one in main and just operate on the one in the file object.
 
Last edited:
  • #37
In other words, you can do this:
C++:
#include <iostream>
#include <cstring>
#include <vector>
#include "fileManage.h"
#include "vectorEdit.h"
using namespace std;
int main()
{
  fileClass file;
  vectorClass vectC;

  cout << " Enter the last name: "; cin >> vectC.Dir.lastName;
  cout << endl;
  vectC.printName();
  file.goPrint( vectC ); // pass vectC as an argument
  vectC.printName();
  return 0;
}//End main()

Or do this:

C++:
#include <iostream>
#include <cstring>
#include <vector>
#include "fileManage.h"
#include "vectorEdit.h"
using namespace std;
int main()
{
  fileClass file;

  cout << " Enter the last name: ";
  cin >> file.vectC.Dir.lastName;
  cout << endl;
  file.vectC.printName();
  file.goPrint();
  file.vectC.printName();
  return 0;
}//End main()

But eventually you should rethink the design.
 
  • Like
Likes yungman
  • #38
Jarvis323 said:
In other words, you can do this:
C++:
#include <iostream>
#include <cstring>
#include <vector>
#include "fileManage.h"
#include "vectorEdit.h"
using namespace std;
int main()
{
  fileClass file;
  vectorClass vectC;

  cout << " Enter the last name: "; cin >> vectC.Dir.lastName;
  cout << endl;
  vectC.printName();
  file.goPrint( vectC ); // pass vectC as an argument
  vectC.printName();
  return 0;
}//End main()

Or do this:

C++:
#include <iostream>
#include <cstring>
#include <vector>
#include "fileManage.h"
#include "vectorEdit.h"
using namespace std;
int main()
{
  fileClass file;

  cout << " Enter the last name: ";
  cin >> file.vectC.Dir.lastName;
  cout << endl;
  file.vectC.printName();
  file.goPrint();
  file.vectC.printName();
  return 0;
}//End main()

But eventually you should rethink the design.
Thanks so much for you reply, I kind of thinking about this a little. It's getting quite complicate that's why I post the question first. Sounds like I am forcing it at this point, do you agree?

If so, I am not going to push it, there is a line to draw between adventurous and stupidity and I feel I am reaching this line forcing myself to use two header files and resort to passing argument like this.

Would you think it's better for me to put everything in one header file, then just use an implementation file to house all the member function just like everyone else does? I know this program will work at this point, seems like I am holding myself back. Maybe it's better off to complete the program and start studying new materials that are waiting for me.

Thanks so much for your help and support. Thanks for the insight in keeping things local. That's something I will follow closely so I don't have to keep tract of them.

Thanks
 
  • #39
yungman said:
Thanks so much for you reply, I kind of thinking about this a little. It's getting quite complicate that's why I post the question first. Sounds like I am forcing it at this point, do you agree?

If so, I am not going to push it, there is a line to draw between adventurous and stupidity and I feel I am reaching this line forcing myself to use two header files and resort to passing argument like this.

Would you think it's better for me to put everything in one header file, then just use an implementation file to house all the member function just like everyone else does? I know this program will work at this point, seems like I am holding myself back. Maybe it's better off to complete the program and start studying new materials that are waiting for me.

Thanks so much for your help and support. Thanks for the insight in keeping things local. That's something I will follow closely so I don't have to keep tract of them.

Thanks

Yeah, it seems you need to progress further in the book before you have the knowledge to make good decisions on how to organize and design your code into different classes. But it is by making mistakes that you learn. I wouldn't set the goal as just having a program that runs in the end. I would try to use the opportunity to learn something. The time spent trying to wrap your head around the problems is well spent, but it could cost a lot of wasted time if you're missing the prerequisite knowledge. When I was learning, I went through stretches of just programing, and then stretches of reading, back and forth. You should be able to tell when you're ready to pick up the book again.
 
  • Like
Likes yungman
  • #40
Jarvis323 said:
Yeah, it seems you need to progress further in the book before you have the knowledge to make good decisions on how to organize and design your code into different classes. But it is by making mistakes that you learn. I wouldn't set the goal as just having a program that runs in the end. I would try to use the opportunity to learn something. The time spent trying to wrap your head around the problems is well spent, but it could cost a lot of wasted time if you're missing the prerequisite knowledge. When I was learning, I went through stretches of just programing, and then stretches of reading, back and forth. You should be able to tell when you're ready to pick up the book again.
Yes, I feel I am not just missing a line of code, I am missing a chunk of knowledge to do this. There comes a point that in order for me to keep pushing, I have to rely on you and others to help, that's not fair to take up your time. particularly you think I am not partitioning the program right, so at best if I make it work, it's half A$$ anyway. That's the most discouraging thing. I am already starting to condense back to one header file to make it work, then I push member function into Implementation file and call it a day. With any luck, I should be able to do it in a day and I can get back to the book.

Like I spent a week to reinvent the binary sort! I think I put enough time on this program. I am pretty sure in half a year and looking back to this program, it's stupid anyway. First, I am going to take a break tonight, I have not have a day off for over 3 weeks already working over 8 hours a day on C++.

Thanks for your help and support.

Alan
 
  • #41
yungman said:
Yes, I feel I am not just missing a line of code, I am missing a chunk of knowledge to do this. There comes a point that in order for me to keep pushing, I have to rely on you and others to help, that's not fair to take up your time. particularly you think I am not partitioning the program right, so at best if I make it work, it's half A$$ anyway. That's the most discouraging thing. I am already starting to condense back to one header file to make it work, then I push member function into Implementation file and call it a day. With any luck, I should be able to do it in a day and I can get back to the book.

Like I spent a week to reinvent the binary sort! I think I put enough time on this program. I am pretty sure in half a year and looking back to this program, it's stupid anyway. First, I am going to take a break tonight, I have not have a day off for over 3 weeks already working over 8 hours a day on C++.

Thanks for your help and support.

Alan
It's the journey that's important, not the destination. This is your mental exercise building your brain stronger. I organized/designed a lot of programs poorly before. It might not be until you've made those mistakes that you really understand why one way is better than another.
 
  • Like
Likes yungman
  • #42
I spent more than a day debugging the program. Seems like it's very important to close the file after use. I still have not pin point where is the problem as I still have trouble with VS that is very inconsistent. I cannot consistently reproduce results. But one thing is very clear, I know which one work and which doesn't.

Here are two function testFile1 and testFile2. testFile1 works, testFile2 fails.
C++:
void testFile1()//
   {DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail()) { createFile();}
     else { DirFile.close(); readFile(); }
   }//End testFile()

  bool testFile2()//
   { failOpen = false;
     DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail())//1st attempt to open file
        { DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
           if(DirFile.fail())//2nd attempt to open file
              { createFile();//file does not exist, create file
                DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
                if (DirFile.fail()) failOpen = true;//If fail, there is a problem
                else { failOpen = false;}//Successfully created file, no read
              }//end 2nd attempt
           else { failOpen = false;}//else, 2nd attempt successful
        }//End if 1st attempt.
     else { failOpen = false; readFile(); }
  //else open file successfully, read into DirV[]
     return failOpen;
   }//End testFile()

I don't even know how many times I stepped through testFile2 in debug, logic is correct but missing DirFile.close() in some conditional statements.

Seems like forgetting to close a file is MORE THAN just "bad habbit", it can create bad reading results. Is this true?

I am getting very close to finish the program. I still have not taking out member function from Specification file to create Implementation file yet. I hope to get to the bottom of this closing file issue.

Regarding to VS, I cannot consistently duplicate the problem BUT at least I actually write down the notes and screen capture the problem when it happened. I tried Rebuild solution and Clean solution and even exit the program, they did not help, but when I reset the computer, it stop g iving me this erroneous results. This is my notes for whatever it's worth. This is not that important at this point as I don't want to make it a trashing VS post, it is what it is.
 

Attachments

  • #43
yungman said:
I spent more than a day debugging the program. Seems like it's very important to close the file after use. I still have not pin point where is the problem as I still have trouble with VS that is very inconsistent. I cannot consistently reproduce results. But one thing is very clear, I know which one work and which doesn't.

Here are two function testFile1 and testFile2. testFile1 works, testFile2 fails.
C++:
void testFile1()//
   {DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail()) { createFile();}
     else { DirFile.close(); readFile(); }
   }//End testFile()

  bool testFile2()//
   { failOpen = false;
     DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail())//1st attempt to open file
        { DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
           if(DirFile.fail())//2nd attempt to open file
              { createFile();//file does not exist, create file
                DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
                if (DirFile.fail()) failOpen = true;//If fail, there is a problem
                else { failOpen = false;}//Successfully created file, no read
              }//end 2nd attempt
           else { failOpen = false;}//else, 2nd attempt successful
        }//End if 1st attempt.
     else { failOpen = false; readFile(); }
  //else open file successfully, read into DirV[]
     return failOpen;
   }//End testFile()

I don't even know how many times I stepped through testFile2 in debug, logic is correct but missing DirFile.close() in some conditional statements.

Seems like forgetting to close a file is MORE THAN just "bad habbit", it can create bad reading results. Is this true?

I am getting very close to finish the program. I still have not taking out member function from Specification file to create Implementation file yet. I hope to get to the bottom of this closing file issue.

Regarding to VS, I cannot consistently duplicate the problem BUT at least I actually write down the notes and screen capture the problem when it happened. I tried Rebuild solution and Clean solution and even exit the program, they did not help, but when I reset the computer, it stop g iving me this erroneous results. This is my notes for whatever it's worth. This is not that important at this point as I don't want to make it a trashing VS post, it is what it is.
Yes, you must close the file. I've also never repeatedly tried to open the same file. If it doesn't open the first time, but does the second time, it can only be due to a more serious problem, like other programs creating and deleting it, your hard drive failing, or something like that.

If it's the behavior of the program when you run it that is inconsistent, then that is not an issue with visual studio, it's because the effects of memory corruption are inconsistent, because it depends on what you've corrupted. In C and C++, it's your responsibility to not corrupt memory, not just the compilers. Make sure you close the files, and make sure you don't go out of bounds in the vectors.

If it compiles sometimes and not others, then it's because somehow you aren't compiling the same code. If you're sure you saved the file, then take a program that compiles, and then make an obvious error in just the header file, and see if the program still compiles. If it does, then VS isn't tracking changes to the header file...

If none of those are the problem, then I don't know, maybe your computer has been compromised by hackers or something.
 
Last edited:
  • Like
Likes yungman
  • #44
Thanks Jarvis323, I kind of thinking that I am over doing it on the checking error. I'll fix that first.

Thanks
 
  • #45
I did it, just missing one step of creating Implementing file. But adding that and add the address, phone, email address are just very simple. The program will ask what you want to do,
a for adding names
s for display complete listing
r for display only 2 before and 3 after the given first 2 characters of the last name.
d for deleting a name, just input the Element#[].
q for quitting.

Enter last name and first name, the program will sort first by last name, then sort the first name if the last names are the same.

It will save in the file upon ending, and when next time loading the program, it will read the file in for more editing.

This is the FileVector.h
C++:
#ifndef fileVector_H
#define fileVector_H
#include <vector>
#include <fstream>
#include <iomanip>
class fileVector
{private:
   const static int nameLen = 25, phoneLen = 16, addLen = 35, eAddLen = 35;
public:
  struct Directory
    {   char lastName[nameLen], firstName[nameLen];
        char address1[addLen], address2[addLen];
        char emailAdd[eAddLen];
        char phone[phoneLen]; int element;
    };
    std::vector<Directory>DirV;
    Directory  Temp; bool newF, failOpen;
    std::fstream DirFile;
bool testFile()//
   { failOpen = false;
     DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail())//1st attempt to open file
        { DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
           if(DirFile.fail())//2nd attempt to open file
              { createFile();//file does not exist, create file
                DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
                if (DirFile.fail()) failOpen = true;//If fail, there is a problem
                else { DirFile.close(); failOpen = false;}//Successfully created file, no read
              }//end 2nd attempt
           else { failOpen = false; DirFile.close();}//else, 2nd attempt successfuel
        }//End if 1st attempt.
     else { failOpen = false; DirFile.close(); readFile(); }
  //else open file successfully, read into DirV[]
     return failOpen;
   }//End testFile()
void writeFile()//Assume file is closed, open file to write DirV[] into file.
  { int ct2 = 0;
    DirFile.open("Directory.dat", std::ios::out | std::ios::binary);
    do
      { DirFile.write(reinterpret_cast<char*>(&(DirV[ct2])),sizeof(DirV[ct2]));
        ct2++;
      } while (ct2 < DirV.size());
    DirFile.close();
  }//End of writeFile
void createFile()
  { DirFile.open("Directory.dat", std::ios::out | std::ios::binary | std::ios::app);
    DirFile.close();
  }
void readFile()//Assume file is OPEN already
  { fileVector::Directory Temp1;
    DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
    while (!DirFile.eof())
      { DirFile.read(reinterpret_cast<char*>(&(Temp1)), sizeof(Temp1));
        if (DirFile.eof()) { break; }
        DirV.push_back(Temp1);
      }
    DirFile.close();
  }
  void addName(Directory Dir, int& newName)
  { int size, selCase;
    DirV.push_back(Dir);//Push to next available element of DirV.
    size = DirV.size();// DirV[midPt].element = midPt; newName = midPt;
    int startPt = 0, endPt = size - 2, midPt = (endPt - startPt) / 2;
    if ((size == 1) || ((strcmp(DirV[endPt].lastName, Dir.lastName) <= 0) & (size >= 2)))
        selCase = 0;//Don't have to sort or anything, Dir is in last element already
  //Case 0 for first entry when size = 1 OR when Dir.lastName is
  // >= to last element of DirV(Dir.lastName >= DirV[endPt].lastName.
    else
    { if ((strcmp(Dir.lastName, DirV[startPt].lastName) <= 0) && (size > 1))
       selCase = 1;//If Dir smaller than DirV[0] AND (size >1)
      else
        { startPt = 0, endPt = size - 2; midPt = (endPt - startPt) / 2;
          do { if (strcmp(Dir.lastName, DirV[midPt].lastName) <= 0)
               { endPt = midPt; midPt = (startPt + endPt) / 2;}
              else { startPt = midPt; midPt = (startPt + endPt) / 2; }
             } while (startPt != midPt);
          selCase = 2;
        }//else selCase = 2
    }//End if((strcmp(Dir.lastName, DirV[startPt].lastName) <= 0) && (size > 1))
   switch (selCase)
        //(size = 1)  AND  Dir.lastName => DirV[endPt].lastName
    { case 0: { DirV[size - 1].element = size - 1; newName = size - 1; break; }
      case 1://Dir.lastName <= DirV[0].lastName
        { int i;
          for (i = 1; i <= (size - 1); i++)
           { DirV[size - i] = DirV[size - i - 1];
             DirV[size - i].element = size - i;
             DirV[size - i - 1].element = size - i - 1;
           }//End for
          DirV[size - i] = Dir; newName = size - i;
          DirV[size - i].element = size - i;
          break;
        };//End case 1
      case 2:
        { int j;
          for (j = 1; j <= (size - endPt - 1); j++)
           { DirV[size - j] = DirV[size - j - 1];
             DirV[size - j].element = size - j;
             DirV[size - j - 1].element = size - j - 1;
           }
          DirV[size - j] = Dir; newName = size - j;
          DirV[size - j].element = size - j;
          break;
        };//end case 2
    };//End switch
   }
  void sort_firstName(int& newName)//DirV[newName] is the newly added name.
    { int beginLname = newName, endLname = newName;//start out all equal
      int bubbleDown, bubbleUp;
      Temp = DirV[newName];//Temporary structure variable
      bool doneUp = false, doneDown = false, moveUp = false;
      bubbleUp = newName; bubbleDown = newName;
      while ((bubbleUp > 0) & !doneUp)//Prevent bubbleUp going negative
        {if ((strcmp(DirV[newName].lastName, DirV[newName - 1].lastName) == 0)
            & (strcmp(DirV[newName].firstName, DirV[newName - 1].firstName) < 0))
           { DirV[newName] = DirV[newName - 1]; DirV[newName].element = newName;
             DirV[newName - 1] = Temp; DirV[newName - 1].element = newName - 1;
             newName--; bubbleUp--; moveUp = true;
           }
         else (doneUp = true);
        }//END while((bubbleUp > 0)& !doneUp)
      if (moveUp == false)
       { while ((bubbleDown < (DirV.size() - 1)) & !doneDown)
          { if ((strcmp(DirV[newName].lastName, DirV[newName + 1].lastName) == 0)
                & (strcmp(DirV[newName].firstName, DirV[newName + 1].firstName) > 0))
             { DirV[newName] = DirV[newName + 1]; DirV[newName].element = newName;
               DirV[newName + 1] = Temp; DirV[newName + 1].element = newName + 1;
               newName++; bubbleDown++;
             }
            else doneDown = true;
          }//END while (decrement < bubbleUp)
       }
    }
  void showRange(char selName[25])
  { int size = DirV.size(), stpt = 0, edpt = size - 1;
    int mdpt = (stpt + edpt) / 2, index, comp;
    do //search to within range using 2 characters in selName
     { comp = strncmp(selName, DirV[mdpt].lastName, 2);
       if (comp != 0)
         { if (comp > 0) { stpt = mdpt; mdpt = (stpt + edpt) / 2; }
           else { edpt = mdpt; mdpt = (stpt + edpt) / 2; }
         }
     } while ((comp != 0) && (stpt + 2 <= edpt));//Matching DirV[mdpt]
     for (index = -2; index <= 3; index++)
      { if (((mdpt + index) >= 0) && ((mdpt + index) <= (size - 1)))
        {std::cout << "   Element #" << DirV[mdpt + index].element <<
            "]  is:   Last name: " << std::left << std::setw(10) << DirV[mdpt + index].lastName <<
             " first name: " << std::left << std::setw(10) << DirV[mdpt + index].firstName << "\n\n";
        }
      }//End for loop to display range of names if it is valid.
   }//End showRange
  void deleteName(int numDelete)
  { char sure;
    int edpt = DirV.size() - 1;
    std::cout << " Is this what you chose?\n";
    std::cout << "   Element #" << DirV[numDelete].element <<
        "]  is:   Last name: " << std::left << std::setw(10) << DirV[numDelete].lastName <<
        " first name: " << std::left << std::setw(10) << DirV[numDelete].firstName << "\n\n";
    std::cout << " Are you sure you want to delete this:\n\n"; std::cin >> sure;
    if (tolower(sure) == 'y')
      { for (int i = 0; i < (edpt - numDelete); i++)
        { DirV[numDelete + i] = DirV[numDelete + i + 1];
          DirV[numDelete + i].element = numDelete + i;
        }
        DirV.pop_back();
    }
  }
};
#endif

Here is the main Source.cpp:
C++:
#include <iostream>
#include <cstring>
#include <vector>
#include <iomanip>
#include "fileVector.h"
using namespace std;
fileVector fileV;

int main()
{
  int newName, index = 0, compSize, numDelete;
  char more, displayAll, choice;
  char selName[25];
  fileVector::Directory Temp2, Temp3;
  cout << " Welcome to the directory program. You can add name, contact\n";
  cout << " informations and it will store in a file. You can display selected\n";
  cout << " names and choose to delete anyone you want.\n\n";
  if (fileV.testFile() == true)
    { cout << " Problem opening file.\n\n"; return 0;}
  do {cout << " Please enter 'a' to add names, 's' to dispay complete list. 'r' to\n";
      cout << " show range of names. 'd' to delete a specific name. 'q' to quit.\n\n";
      cout << " Please enter what you want to do:  "; cin >> choice; cout << "\n\n";
      switch (choice)
       {
        case 'a': //Add new names and sort
         { do {cout << " Enter last name:  "; cin >> Temp2.lastName;
               cout << " Enter first name:  "; cin >> Temp2.firstName;
               fileV.addName(Temp2, newName);
               fileV.sort_firstName(newName);
               cout << " \n\nDo you want to enter another name?  ";
               cin >> more; cout << endl;
              } while (tolower(more) == 'y');
          break;
         };//End case 'a'
        case 's': //Display entire list of names and info
         { index = 0;
           if (fileV.DirV.size() > 0)
            {do { cout << "   Element #[" << fileV.DirV[index].element <<
               "]  is: Name: " << left << setw(15) << fileV.DirV[index].lastName <<
                 fileV.DirV[index].firstName << "\n\n";
                  index++;
                } while (index < fileV.DirV.size());
             }
           else cout << " There is no name in the file.\n\n";
           break;
         };//End case 's'
        case 'r':
         {if (fileV.DirV.size() > 0)
           {cout << " Enter the first 2 character of the last name to search.";
            cin >> selName; cout << "\n\n";
            fileV.showRange(selName);//Display range before and after the name.
           }//End if (fileC.DirV.size() > 0)
          else cout << " There is no name in the file.\n\n";
          break;
         };//End case 'r'
        case 'd'://Delete a name.
          {if (fileV.DirV.size() > 0)
            {fileV.showRange(selName);
             cout << " Enter the Element# of the left to be deleted: ";
             cin >> numDelete;
             fileV.deleteName(numDelete);
            }
           else cout << " There is no name in the file.\n\n";
           break;
          };//End case 'd'
        case 'q': { cout << " Are you sure you want to quit? ";
            cin >> choice; cout << "\n\n"; break;
            };
        default: cout << " Not a valid choice.\n";
        }//End switch
    } while (choice != tolower('q'));//End choice what to do
    fileV.writeFile();
    return 0;
}//End main()

It's been a long road! Thanks for all the help from everyone.
 
Last edited:
  • Like
Likes Jarvis323
  • #46
I finally completed the program, add in the address, email, phone to the list. I created 2 Implementation files to shorten the size of the source.cpp and header file. I actually entered real names and information and it works. Here are the different files. I don't really know how to partition the program, honestly, I just off load as much as possible to the Implementation files. I have on fileManage.cpp for handling files and vectorManage.cpp to do all the sorting and working on the vector.

This is the main Source.cpp
C++:
#include <iostream>
#include <cstring>
#include <vector>
#include <iomanip>
#include "fileVector.h"
using namespace std;
fileVector fileV;
int main()
{
  int newName, index = 0, compSize, numDelete;
  int nameLen = 25, phoneLen = 16, addLen = 41, eAddLen = 35;
  char more, displayAll, choice;
  char selName[25];
  fileVector::Directory Temp2, Temp3;
  cout << " Welcome to the directory program. You can add name, contact\n";
  cout << " informations and it will store in a file. You can display selected\n";
  cout << " names and choose to delete anyone you want.\n\n";
  if (fileV.testFile() == true)
    { cout << " Problem opening file.\n\n"; return 0;}
  do {cout << " Please enter 'a' to add names, 's' to dispay complete list. 'r' to\n";
      cout << " show range of names. 'd' to delete a specific name. 'q' to quit.\n\n";
      cout << " Please enter what you want to do:  "; cin >> choice; cout << "\n\n";
      cin.ignore();
      switch (choice)
       {
        case 'a': //Add new names and sort
           {  fileV.caseA(); break; };//End case 'a'
        case 's': //Display entire list of names and info
           {  fileV.caseS(); break; };//End case 's'
        case 'r':
           {  fileV.caseR(selName); break;};//End case 'r'
        case 'd'://Delete a name.
           {  fileV.caseD(); break;};//End case 'd'
        case 'q': { cout << " Are you sure you want to quit? ";
                    cin >> choice; cout << "\n\n"; break;
                  };
        default: cout << " Not a valid choice.\n";
        }//End switch
    } while (choice != tolower('q'));//End choice what to do
    fileV.writeFile();
    return 0;
}//End main()

This is the Specification file fileVector.h
C++:
#ifndef fileVector_H
#define fileVector_H
#include <vector>
#include <fstream>
#include <iomanip>
#include <iostream>
class fileVector
{private:
   const static int nameLen = 25, phoneLen = 16, addLen = 41, eAddLen = 35;
public:
  struct Directory
    {   char lastName[nameLen], firstName[nameLen];
        char address1[addLen], address2[addLen];
        char emailAdd[eAddLen];
        char phone[phoneLen]; int element;
    };
    std::vector<Directory>DirV;
    Directory  Temp, Temp2; bool newF, failOpen;
    std::fstream DirFile;

  void caseA()//For entering new names and sort
   { char more; int newName;
     do{std::cout << " Enter last name:  "; std::cin.getline(Temp2.lastName, nameLen);
        std::cout << " Enter first name:  "; std::cin.getline(Temp2.firstName, nameLen);
        std::cout << " Enter street number and street: ";
        std::cin.getline(Temp2.address1, addLen);
        std::cout << " Enter city, state and zip: "; std::cin.getline(Temp2.address2, addLen);
        std::cout << " Enter phone number: "; std::cin.getline(Temp2.phone, phoneLen);
        std::cout << " Enter email address: "; std::cin.getline(Temp2.emailAdd, eAddLen);
        addName(Temp2, newName);
        sort_firstName(newName);
        std::cout << " \n\nDo you want to enter another name?  ";
        std::cin >> more; std::cout << "\n\n"; std::cin.ignore();
       } while (tolower(more) == 'y');
   }
  void caseS()//To display entire list of contacts
   { int index = 0;
     if (DirV.size() > 0)
       {do { std::cout << " Element #" << DirV[index].element <<
              " " << DirV[index].lastName << "  " << DirV[index].firstName << "\n";
             std::cout << "            " << DirV[index].address1 << "\n";
             std::cout << "            " << DirV[index].address2 << "\n";
             std::cout << "            Phone: " << DirV[index].phone <<"\n";
             std::cout << "            Email: " << DirV[index].emailAdd << "\n\n";
             index++;
           } while (index < DirV.size());
       }
     else std::cout << " There is no name in the file.\n\n";
   }
  void caseR(char selName[25])//To display a range
    {if (DirV.size() > 0)
       {std::cout << " Enter the first 2 character of the last name to search.";
        std::cin >> selName; std::cout << "\n\n";
        showRange(selName);//Display range before and after the name.
       }//End if (fileC.DirV.size() > 0)
     else std::cout << " There is no name in the file.\n\n";
    }
  void caseD()
  { int numDelete; char selName[25];
    if (DirV.size() > 0)
     { std::cout << " Enter the first 2 character of the last name to search.";
       std::cin >> selName; std::cout << "\n\n";
       showRange(selName);
       std::cout << " Enter the Element# of the left to be deleted: ";
       std::cin >> numDelete;
       deleteName(numDelete);
     }
    else std::cout << " There is no name in the file.\n\n";
  }

//The follow 4 member functions are in fileManage.cpp
    bool testFile();//
    void writeFile();//Assume file is closed, open file to write DirV[] into file.
    void createFile();
    void readFile();//Assume file is OPEN already
//The follow 4 member functions are in vectorManage.cpp
    void addName(Directory , int&);
    void sort_firstName(int& );//DirV[newName] is the newly added name.
    void showRange(char[] );
    void deleteName(int );
};
#endif

This is vectorManage.cpp:
C++:
#include <vector>
#include <iomanip>
#include <iostream>
#include "fileVector.h"
void fileVector::addName(Directory Dir, int& newName)
  { int size, selCase;
    DirV.push_back(Dir);//Push to next available element of DirV.
    size = DirV.size();// DirV[midPt].element = midPt; newName = midPt;
    int startPt = 0, endPt = size - 2, midPt = (endPt - startPt) / 2;
    if ((size == 1) || ((strcmp(DirV[endPt].lastName, Dir.lastName) <= 0) & (size >= 2)))
        selCase = 0;//Don't have to sort or anything, Dir is in last element already
  //Case 0 for first entry when size = 1 OR when Dir.lastName is
  // >= to last element of DirV(Dir.lastName >= DirV[endPt].lastName. 
    else
    { if ((strcmp(Dir.lastName, DirV[startPt].lastName) <= 0) && (size > 1))
       selCase = 1;//If Dir smaller than DirV[0] AND (size >1)
      else
        { startPt = 0, endPt = size - 2; midPt = (endPt - startPt) / 2;
          do { if (strcmp(Dir.lastName, DirV[midPt].lastName) <= 0)
               { endPt = midPt; midPt = (startPt + endPt) / 2;}
              else { startPt = midPt; midPt = (startPt + endPt) / 2; }
             } while (startPt != midPt);
          selCase = 2;
        }//else selCase = 2
    }//End if((strcmp(Dir.lastName, DirV[startPt].lastName) <= 0) && (size > 1))
   switch (selCase)
        //(size = 1)  AND  Dir.lastName => DirV[endPt].lastName
    { case 0: { DirV[size - 1].element = size - 1; newName = size - 1; break; }
      case 1://Dir.lastName <= DirV[0].lastName
        { int i;
          for (i = 1; i <= (size - 1); i++)
           { DirV[size - i] = DirV[size - i - 1];
             DirV[size - i].element = size - i;
             DirV[size - i - 1].element = size - i - 1;
           }//End for
          DirV[size - i] = Dir; newName = size - i;
          DirV[size - i].element = size - i;
          break;
        };//End case 1
      case 2:
        { int j;
          for (j = 1; j <= (size - endPt - 1); j++)
           { DirV[size - j] = DirV[size - j - 1];
             DirV[size - j].element = size - j;
             DirV[size - j - 1].element = size - j - 1;
           }
          DirV[size - j] = Dir; newName = size - j;
          DirV[size - j].element = size - j;
          break;
        };//end case 2
    };//End switch
   }
  void fileVector::sort_firstName(int& newName)//DirV[newName] is the newly added name.
    { int beginLname = newName, endLname = newName;//start out all equal
      int bubbleDown, bubbleUp;
      Temp = DirV[newName];//Temporary structure variable
      bool doneUp = false, doneDown = false, moveUp = false;
      bubbleUp = newName; bubbleDown = newName;
      while ((bubbleUp > 0) & !doneUp)//Prevent bubbleUp going negative
        {if ((strcmp(DirV[newName].lastName, DirV[newName - 1].lastName) == 0)
            & (strcmp(DirV[newName].firstName, DirV[newName - 1].firstName) < 0))
           { DirV[newName] = DirV[newName - 1]; DirV[newName].element = newName;
             DirV[newName - 1] = Temp; DirV[newName - 1].element = newName - 1;
             newName--; bubbleUp--; moveUp = true;
           }
         else (doneUp = true);
        }//END while((bubbleUp > 0)& !doneUp)
      if (moveUp == false)
       { while ((bubbleDown < (DirV.size() - 1)) & !doneDown)
          { if ((strcmp(DirV[newName].lastName, DirV[newName + 1].lastName) == 0)
                & (strcmp(DirV[newName].firstName, DirV[newName + 1].firstName) > 0))
             { DirV[newName] = DirV[newName + 1]; DirV[newName].element = newName;
               DirV[newName + 1] = Temp; DirV[newName + 1].element = newName + 1;
               newName++; bubbleDown++;
             }
            else doneDown = true;
          }//END while (decrement < bubbleUp)
       }
    }
  void fileVector::showRange(char selName[25])
  { int size = DirV.size(), stpt = 0, edpt = size - 1;
    int mdpt = (stpt + edpt) / 2, index, comp;
    do //search to within range using 2 characters in selName
     { comp = strncmp(selName, DirV[mdpt].lastName, 2);
       if (comp != 0)
         { if (comp > 0) { stpt = mdpt; mdpt = (stpt + edpt) / 2; }
           else { edpt = mdpt; mdpt = (stpt + edpt) / 2; }
         }
     } while ((comp != 0) && (stpt + 2 <= edpt));//Matching DirV[mdpt]
     for (index = -2; index <= 3; index++)
      { if (((mdpt + index) >= 0) && ((mdpt + index) <= (size - 1)))
        {std::cout << "   Element #" << DirV[mdpt + index].element <<
            "]  is:   Last name: " << std::left << std::setw(10) << DirV[mdpt + index].lastName <<
             " first name: " << std::left << std::setw(10) << DirV[mdpt + index].firstName << "\n\n";
        }
      }//End for loop to display range of names if it is valid.
   }//End showRange
  void fileVector::deleteName(int numDelete)
  { char sure;
    int edpt = DirV.size() - 1;
    std::cout << " Is this what you chose?\n";
    std::cout << "   Element #" << DirV[numDelete].element <<
        "]  is:   Last name: " << std::left << std::setw(10) << DirV[numDelete].lastName <<
        " first name: " << std::left << std::setw(10) << DirV[numDelete].firstName << "\n\n";
    std::cout << " Are you sure you want to delete this:\n\n"; std::cin >> sure;
    if (tolower(sure) == 'y')
      { for (int i = 0; i < (edpt - numDelete); i++)
        { DirV[numDelete + i] = DirV[numDelete + i + 1];
          DirV[numDelete + i].element = numDelete + i;
        }
        DirV.pop_back();
      }
  }//end deleteName(int numDelete)
This is the fileManage.cpp:
C++:
#include <vector>
#include <fstream>
#include <iomanip>
#include <iostream>
#include "fileVector.h"

bool fileVector::testFile()
   { failOpen = false;
     DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
     if (DirFile.fail())//1st attempt to open file
        { DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
           if(DirFile.fail())//2nd attempt to open file
              { createFile();//file does not exist, create file
                DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
                if (DirFile.fail()) failOpen = true;//If fail, there is a problem
                else { DirFile.close(); failOpen = false;}//Successfully created file, no read
              }//end 2nd attempt
           else { failOpen = false; DirFile.close();}//else, 2nd attempt successfuel
        }//End if 1st attempt.
     else { failOpen = false; DirFile.close(); readFile(); }
  //else open file successfully, read into DirV[]
     return failOpen;
   }//End testFile()
void fileVector::writeFile()//Assume file is closed, open file to write DirV[] into file.
  { int ct2 = 0;
    DirFile.open("Directory.dat", std::ios::out | std::ios::binary);
    do
      { DirFile.write(reinterpret_cast<char*>(&(DirV[ct2])),sizeof(DirV[ct2]));
        ct2++;
      } while (ct2 < DirV.size());
    DirFile.close();
  }//End of writeFile
void fileVector::createFile()
  { DirFile.open("Directory.dat", std::ios::out | std::ios::binary | std::ios::app);
    DirFile.close();
  }
void fileVector::readFile()//Assume file is OPEN already
  { fileVector::Directory Temp1;
    DirFile.open("Directory.dat", std::ios::in | std::ios::binary);
    while (!DirFile.eof())
      { DirFile.read(reinterpret_cast<char*>(&(Temp1)), sizeof(Temp1));
        if (DirFile.eof()) { break; }
        DirV.push_back(Temp1);
      }
    DirFile.close();
  }
I am done with write program.Last question is Mark44 told me how to compile in RELEASE mode instead of DEBUG. Also how to run the program on computers without VS. I cannot find the post. Can Mark or someone kindly tell me what to do to generate and how to use in another computer?

Thanks for all the help.

Alan
 
  • #47
Jarvis323 said:
Yes, you must close the file. I've also never repeatedly tried to open the same file. If it doesn't open the first time, but does the second time, it can only be due to a more serious problem, like other programs creating and deleting it, your hard drive failing, or something like that.

If it's the behavior of the program when you run it that is inconsistent, then that is not an issue with visual studio, it's because the effects of memory corruption are inconsistent, because it depends on what you've corrupted. In C and C++, it's your responsibility to not corrupt memory, not just the compilers. Make sure you close the files, and make sure you don't go out of bounds in the vectors.

If it compiles sometimes and not others, then it's because somehow you aren't compiling the same code. If you're sure you saved the file, then take a program that compiles, and then make an obvious error in just the header file, and see if the program still compiles. If it does, then VS isn't tracking changes to the header file...

If none of those are the problem, then I don't know, maybe your computer has been compromised by hackers or something.
Now that I have time to look at other things. The VS problem I described in post 42 has nothing to do with memory corruption. It's the same program I've been working on. What I change has nothing to do with memory. I just put '//' in front of line 27 in the source.cpp in post 45. The program is the same as what I used in post 42 except I was working on the file.close() issue that has nothing to do with memory.

The line I commented out just read first name into the buffer Temp2. Did I repeat back and fore to verify that. I rebuild, clean solution, exit program and enter again. It was consistent until I restart the computer.

I am sure I did not corrupt any memory. Actually, after putting file.close() correctly, that's the final program and it's working perfectly. All I can say is something is strange. I am so glad I at least screen captured that. I should have capture the others when I first saw them, or else, it's always I'm the one that screw things up. I captured this step by step, I even described what letter I punched in step by step.

Thanks
 
  • #48
I actually compile the file in RELEASE option. It's very easy, Just copy the application file into a folder and put the .dat file with it. I can just put it in flash drive and copy onto another computer without VS. Just click the application file and the program runs, I can pull the names and phone, address and all. It's so simple, just the application file and the .dat file I created.

The file is small also. The application file is only 31K and the .dat with 6 names is only 2K! It is so fast, everything is like instantaneous.

Thanks everyone for all the help. I just wrote a real program that can by used by people. I am going to send it to my stepson and grand kids to see whether they want to use it.
 
Last edited:
  • #49
I already starting to study chapter 14, learning about friends of a class, That is exactly what I need to have two header files, fileManage.h and vectorManage.h to complete everything I set out to do in my directory program. I am learning friends and I'll modify this program to use two header files. This is how I feel the program should be broken down. It's the most logical of using class, one class to handle vector sorting, adding and deleting. Another class just handling read and write file.
 
  • #50
yungman said:
This is how I feel the program should be broken down. It's the most logical of using class, one class to handle vector sorting, adding and deleting. Another class just handling read and write file.
As has been mentioned before, this is NOT the way your 'Directory' program should be broken down.

Classes should NOT be used to collect fuctions according to what they do, they should be used to collect functions together with the entity they do it to.

Your directory class should have the following public methods:
Code:
Directory::readFile;
Directory::writeFile;
Directory::add;
Directory::find;
Directory::sort;
 
  • Like
Likes yungman and Vanadium 50
  • #51
pbuk said:
As has been mentioned before, this is NOT the way your 'Directory' program should be broken down.

Classes should NOT be used to collect fuctions according to what they do, they should be used to collect functions together with the entity they do it to.

Your directory class should have the following public methods:
Code:
Directory::readFile;
Directory::writeFile;
Directory::add;
Directory::find;
Directory::sort;
Thanks for the reply.

I thought it's more logical to have a class to write and read file with a given vector of structure. Then one class to handle the vector manipulations.

In my mind, ultimately, I want the vectorManage class to receive any vector with a specific member variable used for sorting( second for finer sorting like first name) but NOT specific to last name or first name. Then another class to read write file with a vector and name/destination of the file as parameters. This way, it will be general purpose for other use. for example if I want to do an inventory program with parts given the part number. I can use the same two classes, I can sort the parts and save in file.

With that, I can make the two classes as general purpose. Directory is only one of the program that uses this two classes.

What you suggested is more like a member function within the vectorManage. Isn't better to put those in the Implementation files .cpp?

Thanks
 
Last edited:
  • #52
Repeating @pbuk's post:
pbuk said:
Your directory class should have the following public methods:
Code:
Directory::readFile;
Directory::writeFile;
Directory::add;
Directory::find;
Directory::sort;
yungman said:
I thought it's more logical to have a class to write and read file with a given vector of structure. Then one class to handle the vector manipulations.
Several of us, including pbuk and myself, disagree with your logic here.
yungman said:
With that, I can make the two classes as general purpose. Directory is only one of the program that uses this two classes.
Directory is not a program -- it is the main class in your program. Many of us maintain that it should be the only class.
yungman said:
What you suggested is more like a member function within the vectorManage.
No, not at all. pbuk was very specific in what he wrote. All five functions are members of the Directory class.
yungman said:
Isn't better to put those in the Implementation files .cpp?
I think you might be confused here. The header file for Directory would give the class definition, together with declarations (only) for the member functions. The .cpp file would provide the definitions (the bodies) of those member functions.
 
Last edited:
  • Like
Likes sysprog and Vanadium 50
  • #53
Mark44 said:
Repeating @pbuk's post:
Several of us, including pbuk and myself, disagree with your logic here.
Directory is not a program -- it is the main class in your program. Many of us maintain that it should be the only class.
No, not at all. pbuk was very specific in what he wrote. All five functions are members of the Directory class.
I think you might be confused here. The header file for Directory would give the class definition, together with declarations (only) for the member functions. The .cpp file would provide the definitions (the bodies) of those member functions.
I thought class should be a template to perform certain function, not just splitting up the program to smaller pieces.

I know you all said I am taking too big of a bite, But this is a goal that I want to pursue. I look at a class should be more general purpose that other programs can use. Like I envision a class of vector management that take argument of any structure to store in a vector. The structure has a member say called mainSort(Used as last name in my program) that the vector class know to use it to sort the order. Then another member of the structure called say fineSort(used as firstname) to refine sorting. The vectorManage class also perform adding, deleting. Then another general purpose fileManage class to take in the pointer to a vector and the name/location of the file as two arguments to read and write files of different names and into different locations.

I thought this is the goal of having classes that different programs can use. I can envision Inventory program can use this, using part number ( in character) for sorting, you then can have cost, description and others which vectorManage class doesn't even care as long as it knows to sort the order. Then a general purpose fileManage class to just blindly read and write to file according to argument of the pointer to the vector AND the file name and location.

I envision I can do Employee information and some other programs that need to use these two classes.

I know, this is again a big step, but hey, one can dream. Using friends is ONLY the first step that I know to make the program to have two header files, that is more important than anything else at this point for me. Doing the program in my ultimate goal is still quite far off. But one step at a time.
 
  • #54
yungman said:
I thought class should be a template to perform certain function
No. A class should represent some thing. The class should contain all the methods that are needed by whatever the thing is -- methods for creating and destroying the thing, updating the thing, and so on.
yungman said:
I look at a class should be more general purpose that other programs can use. Like I envision a class of vector management that take argument of any structure to store in a vector.
You're not thinking in terms of object oriented programming. Instead, what you're doing is procedural programming with a thin veneer of classes.
yungman said:
I thought this is the goal of having classes that different programs can use.
Right, it is. But a class should represent some thing, like a Person or a Directory or a Widget. You are not doing object-oriented programming (OOP) if you have one class for, say, entering a person, and another for saving that person's data to disk.
yungman said:
Using friends is ONLY the first step that I know to make the program to have two header files, that is more important than anything else at this point for me.
Why is it important to have two header files? You're letting this goal get in the way of understanding good object-oriented programming design.
 
Last edited:
  • Like
Likes Vanadium 50, sysprog, yungman and 1 other person
  • #55
yungman said:
I look at a class should be more general purpose that other programs can use.

That is called a library, like the Standard Template Library (STL). The classes you (and I, and 99% of all programmers) write are not libraries, they use libraries that other people have written to implement functionality specific to the entity.

yungman said:
Like I envision a class of vector management that take argument of any structure to store in a vector.

That is what std::vector is.

yungman said:
The structure has a member say called mainSort(Used as last name in my program) that the vector class know to use it to sort the order. Then another member of the structure called say fineSort(used as firstname) to refine sorting.

std::sort exists to sort vectors.

yungman said:
The vectorManage class also perform adding, deleting.
std::vector is not very well suited to deleting elements; you would be better off with std::list or std::map.

STOP trying to guess for yourself what Object Oriented Programming means and learn it properly. If you are not picking this up from the book you are using, ask for some more examples. Here are some: https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html.
 
  • Like
Likes sysprog, Vanadium 50, yungman and 1 other person
  • #56
Ah! So class is NOT like library or Template type of general purpose. I thought that's what class is for!

But then I fail to see what's class for, other than just separate function into separate files instead writing all the functions in one big program.

So what I did is ok, I just stuff all the little file in .cpp and get over with it.

I can't wait to study library and Template.
 
  • #57
yungman said:
But then I fail to see what's class for,
In your application it would make sense to have a class called Directory for doing every thing you want to do with a Directory (load from disk, add an Entry, sort etc.). It might also make sense to have a class called Entry for doing everything you want to do with a directory entry (add an email address, change the name to correct a typo etc.), replacing the struct you are currently using for directory entries. I have seen classes in C++ introduced as 'structs on steroids', although like all analogies you can take this too far.

yungman said:
other than just separate function into separate files instead writing all the functions in one big program.
In a way that is exactly what we are doing - although because we are not just separating functions but also variables, constants etc. we say we are separating concerns into different files. 'Separation of concerns' is an important goal in programming; it means when something is broken you know where to start looking to fix it.

In your program you might have 4 files:
FileConcern
main.cppReading from the command line and dispatching corresponding actions
directory.hSpecifying the interface for the Directory class
directory.cppImplementing everything concerned with Directories
entry.hSpecifying the interface for the Entry class
entry.cppImplementing everything concerned with Entries
 
  • Like
Likes sysprog and yungman
  • #58
pbuk said:
In your application it would make sense to have a class called Directory for doing every thing you want to do with a Directory (load from disk, add an Entry, sort etc.). It might also make sense to have a class called Entry for doing everything you want to do with a directory entry (add an email address, change the name to correct a typo etc.), replacing the struct you are currently using for directory entries. I have seen classes in C++ introduced as 'structs on steroids', although like all analogies you can take this too far.In a way that is exactly what we are doing - although because we are not just separating functions but also variables, constants etc. we say we are separating concerns into different files. 'Separation of concerns' is an important goal in programming; it means when something is broken you know where to start looking to fix it.

In your program you might have 4 files:
FileConcern
main.cppReading from the command line and dispatching corresponding actions
directory.hSpecifying the interface for the Directory class
directory.cppImplementing everything concerned with Directories
entry.hSpecifying the interface for the Entry class
entry.cppImplementing everything concerned with Entries
Ha ha, this is so anti climatic! I was so excited and wrote this big program thinking I am a step ahead. If I knew all these, I might not even write the program. It's just external function with a twist. I think I am going to take a day off today. I was so excited about this thinking I can make a general purpose function to be called and I think so hard about this. What a let down. But thanks for telling me about this, it's better knowing this now than to waste another two weeks doing more stupid things.

One thing though, I think I learn this part of class pretty good because of all these. I spent the whole day yesterday stepping through the programs with friends step by step to make sure I understand and nothing left behind! Now I just want to get to the overload part and looking forward to library and template stuffs before I get back to the program again.

Thanks
 
  • #59
Question: Is class most useful in splitting up a big program in logical way so more people can work on the program at the same time with the given spec and arguments passing. A good way to logically splitting up a big program?

Like the main program create the vector of structure, then call
1) A class of user interface to get the information and return to main().
2) main() call a sorting class to add the new info by passing the vector by reference to have the sorting class to add, sort and the vector.
3) main() call class for delete a name by passing vector by reference and name to delete and the class modify the vector.
4) When quiting the program, main() call the file class to write the vector to file.

This way, you can have different person writing one of the class without knowing each other, all they need is the reference to the vector and what to change etc.

Am I getting this correct? If this is so, I have a much better idea how to split the program. Main thing is to make sure each class don't interact with each other, everything control by main(). Without classes interact with each other, I don't need friends and all that, just a lot of different classes.

thanks
 
Last edited:
  • #60
yungman said:
Question: Is class most useful in splitting up a big program in logical way so more people can work on the program at the same time with the given spec and arguments passing. A good way to logically splitting up a big program?
No.
You can have a single class with the class methods implemented in multiple files. The class method implementations don't have to reside in just a single file. It's exactly the same in C or in non-OO C++ programs -- you could have main() in one file, and multiple other files in the project that each contain one function. Multiple people could work on the separate parts individually.
yungman said:
Like the main program create the vector of structure, then call
1) A class of user interface to get the information and return to main().
2) main() call a sorting class to add the new info by passing the vector by reference to have the sorting class to add, sort and the vector.
3) main() call class for delete a name by passing vector by reference and name to delete and the class modify the vector.
4) When quiting the program, main() call the file class to write the vector to file.
You're really missing the point of object-oriented programming, where the key idea is the object. What you describe above could just as well be done in any procedural language, like Fortran or Pascal or even C.
It really makes no sense at all to partition the program in the way you describe, with separate classes for getting the information, sorting the directory, deleting a name, storing the information to disk. Again the focus should be on the things that you're working with - the Directory and the entries that represent the individuals whose information will be in the directory.

The focus should not be the operations you want to perform on the objects.

There's a saying:
If the only tool you have is a hammer, everything looks like a nail.
You've learned a little bit about classes, and now you think everything should be a class. As was recommended earlier, it would be a good idea to back off for a bit, and learn something about how to design an object-oriented program.

@pbuk has given you some good advice that you seem to be ignoring.
pbuk said:
In your application it would make sense to have a class called Directory for doing every thing you want to do with a Directory (load from disk, add an Entry, sort etc.). It might also make sense to have a class called Entry for doing everything you want to do with a directory entry (add an email address, change the name to correct a typo etc.), replacing the struct you are currently using for directory entries.

yungman said:
Am I getting this correct?
Not at all.
 
Last edited:
  • Like
Likes pbuk and sysprog

Similar threads

  • · Replies 36 ·
2
Replies
36
Views
4K
Replies
12
Views
3K
  • · Replies 30 ·
2
Replies
30
Views
4K
  • · Replies 89 ·
3
Replies
89
Views
6K
Replies
4
Views
2K
  • · Replies 66 ·
3
Replies
66
Views
5K
  • · Replies 32 ·
2
Replies
32
Views
3K
Replies
5
Views
2K
Replies
20
Views
2K
Replies
10
Views
2K