Help in my program using Classes

In summary: Case = dirCase(DirV[midPt].element, Dir.lastName); }//End addName void deleteName(int& oldName) { int size, selCase; DirV.pop_back();//Remove the element at position DirV.size() - 1 size = DirV.size();//DirV[midPt].element = midPt; oldName = midPt; int startPt = 0, endPt = size - 2, midPt = (endPt
  • #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:
Technology news on Phys.org
  • #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

  • Problem with Directory 3.docx
    133.1 KB · Views: 142
  • #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
  • #61
Well, I guess I give up, I just don't see what class is for anymore. I just get my program done the best way I know how and learn along the way. I can see the usefulness of structure as template, I totally don't see the point of class other than split one big file into many smaller files that can be done separately, helping to make the flow cleanly so signal( variables ) are not intertwine together. Way to make a clean divide the task for each module. AND of cause be able to split the task up so other people can work in parallel. That is about to most important thing in real life working environment. If not for that, I am not interested in the academic definition what the class supposed to do. Programming regardless of OOP or procedural, or any languages, are only tools, it's a means to an end, not the end of the means.

I might not experienced in programming, BUT believe me, I design and in charge a lot of big systems from top down for a really long time with success, how to divide project to different people, how to divide according to the function and clean interface. How to make it so I can change one module and not affecting the others as much as possible. This is from real life experience AND interfaced with a lot of software people. This is the way I would do if I write a program. AND I TRUST my experience.
 
Last edited:
  • #62
The point of OOP is to make it easier for programmers and teams of programmers. It is intended to be more modular, to strengthen the distinction between implementation and interface, to allow more code reuse and reduce code duplication.

If you don't see the value, it is likely a combination of being new to this, and not following the advice of people like @pbuk and @Mark44 who have more experience - probably many thousand times as many lines of code.
 
  • #63
yungman said:
Well, I guess I give up, I just don't see what class is for anymore.
The book that you're using (Gaddis) tells you this. In my copy, the first edition, Gaddis describes the difference between procedural programming and object-oriented programming. C++ (and other OO languages provide support for OOP via the class construct.
In procedural programming, the programmer constructs procedures (or functions, as they are called in C++). The procedures are collections of programming statements that perform a specific task. The procedures each contain their own variables and commonly share variables with other procedures.
Object-oriented programming (OOP), on the other hand, is centered around the object. An object is a programming element that contains data and procedures that operate on the data. It is a self-contained unit. The objects contain, within themselves, both information and the ability to manipulate the information.
I'm reasonably certain that the edition you're using, 5th or 6th?, contains the same or similar information, probably in the very first chapter.
yungman said:
I can see the usefulness of structure as template,
In C++, there is essentially no difference between a struct and a class, other than the default access specifier for a struct is public, and the default access specifier for a class is private. Otherwise, there is no difference.
 
  • #64
Mark44 said:
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.
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:

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.Not at all.
Actually, that's very similar to what my Directory program ALREADY in post#46. If you look back to my last program. I have one Specification file to handle both file and vector management. Then I have two separate .cpp files one for all the file read write, one for all the vector sorting. Having individual .cpp for each task is just a more expanded version. BUT, to me it's not clean, that's why I want to modulized even more, at least separate the file I/O from vector.

I get what you say about the class, the book said what you say. The book even said class is the "blue print" of a house and you can build a lot of house with the same blueprint. BUT, in real life, do you really have that many program that have to keep repeating the same "blueprint" over and over within the program? Like in my Directory, I only sort it one time when I add a new name! I don't need "blueprint". It just creating more restrictions in the name of "making lives easier".

What is really really important in real live is being able to logically splitting the big program into smaller individual pieces by having clean parameters interface so people can work in parallel on the program AND more importantly, making it cleaner on signal(variables) flow for easier to troubleshoot.

I only study to chapter 14, there might be other better ways to split the program other than using classes. Just like I did not realize what I want that is very important to make it general purpose is covered in library and template instead of class. But if there is something exist to do the splitting, then the usefulness of class is very limited, nothing more than struct but with a lot more inconvenience.
 
  • #65
yungman said:
Actually, that's very similar to what my Directory program ALREADY in post#46.
Well, you split up the file management functions into multiple files, which is fine, but you still have two classes in your program
yungman said:
BUT, in real life, do you really have that many program that have to keep repeating the same "blueprint" over and over within the program? Like in my Directory, I only sort it one time when I add a new name! I don't need "blueprint". It just creating more restrictions in the name of "making lives easier".
I don't think you understand how the blueprint business works in real world programs (i.e., programs with hundreds of thousands (or more) lines of code, being worked on by large teams of programmers.
A well designed Employee class could be used by programs used by HR, Payroll, Management, or other entities. Each different application would not need to "roll their own" to deal with an employee.
yungman said:
What is really really important in real live is being able to logically splitting the big program into smaller individual pieces by having clean parameters interface so people can work in parallel on the program AND more importantly, making it cleaner on signal(variables) flow for easier to troubleshoot.
If you design a program that is procedural, you get the problem you're describing, where one function has to be extra careful about what its parameters are. As a case in point, in which your interface was not clean and easy to troubleshoot, Jarvis said this (post #22):
Jarvis323 said:
I'm just glancing now. Is the vecC in main the same one in your file object
In main shouldn't you use file.vecC ?
Here was your reply:
yungman said:
I edit this post. I declared std::vector<Directory>DirV; in line 17 of vectorEdit.h, this should make DirV[] global. I should be able to use vectC.DirV in main() and fileManage.h.
Which is not a good solution. With object-oriented programming, done correctly, you don't run into problems like this.
A Directory class would have all the methods it needs to create or delete a directory, add an entry to a directory or remove one from it, save its contents to disk.
 
  • #66
Mark44 said:
......
Here was your reply:
Which is not a good solution. With object-oriented programming, done correctly, you don't run into problems like this.
A Directory class would have all the methods it needs to create or delete a directory, add an entry to a directory or remove one from it, save its contents to disk.
You reading the right post#46? That's the final program, there is no fileManage.h in my program. That's how you described how it should be done. You are looking at the old program that I tried to have two Specification files. In my last program in post #46, I only have one fileVector.h header file. You can call it Directory or fileVector, it does exactly the thing you talked about.

What I want ultimately is to have two header files, one for only vector management with all the sort, add, delete in it. The other is file management that only read and write to file. They can have all the member function in separate Implementation files ( it absolutely does NOT make sense in the book to have Implementation with only one or two line function like int getCrap(){return crap;}) Why pull it out to the .cpp file for routine that is one liner?! AND there will be no interface between the two header files, no friends at all. Clean.
 
  • #67
yungman said:
Clean.
Clean? CLEAN?
  1. It is not clean to hard code the same filename in 6 different places.
  2. It is not clean to use cryptic method names like caseA.
  3. It is not clean to lay your code out randomly:
    1. sometimes placing a { in the same column as the previous statement, sometimes with 1, 2 or 4 additional spaces of indentation
    2. sometimes placing the next statement on the next line, sometimes on the same line as the { after 0, 1, 2 or 3 spaces
    3. etc. etc.
  4. It is not clean to write a comment "Assume file is OPEN already" and 2 lines later open the file.
  5. It is not clean to mix PascalCase and camelCase randomly for variable names.
  6. It is not clean to mix snake_case and camelCase randomly for method names (are you trying to achieve a record with sort_firstName?)
  7. It is not clean to use PascalCase for variable names and camelCase for class names (it IS clean to do this the other way round).
  8. It is not clean to write tolower('q').
  9. It is not clean to try to open the same file twice, do you think the computer tries harder to find it the second time?
  10. etc. etc.
 
  • Like
Likes phinds and Vanadium 50
  • #68
pbuk said:
Clean? CLEAN?
  1. It is not clean to hard code the same filename in 6 different places. It's not wrong.
  2. It is not clean to use cryptic method names like caseA.Correspond to case 'a' which is what the user type in for "adding", r for replacing, d for deleting etc.
  3. It is not clean to lay your code out randomly:
    1. sometimes placing a { in the same column as the previous statement, sometimes with 1, 2 or 4 additional spaces of indentation
    2. sometimes placing the next statement on the next line, sometimes on the same line as the { after 0, 1, 2 or 3 spaces
    3. etc. etc.//Better than no indent. I don't want to start another line and make it harder to read. I hate seeing comment line between lines of codes, That is more disrupting.
  4. It is not clean to write a comment "Assume file is OPEN already" and 2 lines later open the file.//must be a mistake left over when I change the code.
  5. It is not clean to mix PascalCase and camelCase randomly for variable names.
  6. It is not clean to mix snake_case and camelCase randomly for method names (are you trying to achieve a record with sort_firstName?)
  7. It is not clean to use PascalCase for variable names and camelCase for class names (it IS clean to do this the other way round).
  8. It is not clean to write tolower('q').//This is how the book use.
  9. It is not clean to try to open the same file twice, do you think the computer tries harder to find it the second time?//Yes, with the inconsistency of all the computers and hardware. Don't even get me started on this.
  10. etc. etc.
Clean, I mean I am trying to make the program flow cleanly like I described in post#61. I am not good in coding and I made a lot of mistake. I am trying, I never say I am good right now, it's a goal I want to achieve.

To me, name is secondary to the design of the system. At this point where I am the only one that work on the program, I rather have shorter names so I don't have to use more lines. This is VERY IMPORTANT as when I print it out, I try to put the code in a single page, that make it a whole lot easier to read. This is IMPORTANT TO ME.

I have no idea what you are talking about pascal and camel.
 
  • #69
yungman said:
You reading the right post#46?
My comment had nothing to do with post #46. It referred to a comment by Jarvis in post 22, which I mentioned.
Mark44 said:
As a case in point, in which your interface was not clean and easy to troubleshoot, Jarvis said this (post #22):
Right after that, I quoted your post #23.
The comment had to do with why your earlier version was more complicated and difficult to troubleshoot (you had to get help from us here). I was attempting to convince you that an object-oriented design might be easier to work with.

yungman said:
To me, name is secondary to the design of the system. At this point where I am the only one that work on the program, I rather have shorter names so I don't have to use more lines.
If you truly were the only one working on the program, that might make some sense. But that isn't the case, as all of us here who have been reading your code, and trying to make some sense of what you are trying to do.
Choosing self-explanatory names for variables, functions, and classes should not be secondary to the design of a program. Making the code fit in fewer lines -- that should be secondary.
 
  • #70
Mark44 said:
My comment had nothing to do with post #46. It referred to a comment by Jarvis in post 22, which I mentioned.

Right after that, I quoted your post #23.
The comment had to do with why your earlier version was more complicated and difficult to troubleshoot (you had to get help from us here). I was attempting to convince you that an object-oriented design might be easier to work with.

If you truly were the only one working on the program, that might make some sense. But that isn't the case, as all of us here who have been reading your code, and trying to make some sense of what you are trying to do.
Choosing self-explanatory names for variables, functions, and classes should not be secondary to the design of a program. Making the code fit in fewer lines -- that should be secondary.
Yeh, post #22 is a long time ago, I learn a lot since. I thought you comment on post #46 the final version. It's very close to what you want to be.

I really thought I made the names a lot better. Like caseA() stands for what the user type in 'a' to choose adding a name. It is in a switch-case part of the code. I call the header file fileVector exactly what it is doing, working on both file and vector. In my mind, this is as clear as it can.

This is the first time in 4 months I have not even studied a page for two days. I actually questioning whether I want to continue to study C++. I feel very frustrated with it when I read about friends, now Memberwise Assignment and Copy Contruction. It's like the language want to be straight...then when it comes to something inconvenient, then create a back door to bypass it! Specially like the friend thing. I thought it's a good practice to have control of the traffic flow having private and all. BUT than you open the back door when it is inconvenient. Then the Memberwise Assignment, just type an extra line to assign the variables! Why make it so confusing. BUT, if I don't learn it, I won't be able to understand what other people write.

I peeked into the overload section, sounds like it want to use the operator differently with definitions. I don't know the detail, but that is so so discouraging to me. It's is like playing tricks to make the code looks simpler and save a line of two. I don't know how much knowledge I consider in C++. I am only 1 chapter from completing the whole book(the brief version). I was very excited studying chapter 13 on classes, but 14 looks to be all the tricks. I am questioning whether programming is for me or not. I hope I can finish to chapter 16 in the complete book( that has 20 lessons) on library and templates, but it's just getting harder to concentrate with all these in my mind. I feel very frustrated at this point.

Thanks so much for your help in the last few months.
 
Last edited:
Back
Top