Thread: I need to change this program I wrote, from a struct format to a class

  1. #1
    Registered User
    Join Date
    Nov 2016
    Posts
    2

    I need to change this program I wrote, from a struct format to a class

    So basically I worked really hard on this code in my CS150 class and now I need to change it to a class, and I thought OK that's simple enough, but I cant seem to figure it out at all! I know I can just make all of the variables inside the class public, but that's not what my professor wants. I am supposed to implement the private variables. I tried making the "letter" and "letterCount" variables private and I created some void functions under the public part, I think I might have been on the right track with that but I wasn't sure how to modify the rest of my code in order to get it to run. Here's the original code, still in the struct format. Any help would be GREATLY appreciated.


    P.S. my professor said "make the member variables private, and impliment functions to manage those private variables, such as getter and setter functions." so that might help you understand whats expected. Thanks!


    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <iomanip>
    
    
    using namespace std;
    
    
    //Struct definition
    struct letterType
    {
        char letter;
        int letterCount;
    };
    
    
    //Function to open I/O files
    void openFile(ifstream& inFile, ofstream& outFile);
    
    
    //Function to fill the array of structs and keep track of the amount of uppercase/lowercase letters
    void count(ifstream& inFile, letterType letterList[], int& totalBig, int& totalSmall);
    
    
    //Function to print the letters, the occurences, and the percentages
    void printResult(ofstream& outFile, letterType letterList[], int totalBig, int totalSmall);
    //Function to create an output file that contains programmer info
    void Info (ofstream& outputFile);
    
    
    int main()
    {
        ofstream fout;
        ifstream input; //object to read the text
        ofstream output; //object to write the results
        int totalCapital = 0; //variable to store the total number of uppercase
        int totalLower = 0; //variable to store the total number of lowercase
        letterType letterObj[52]; //array of structs of type letterType to hold the information
    
    
        //Input and process data
        Info (fout);
        openFile(input, output);
        count(input, letterObj, totalCapital, totalLower);
        printResult(output, letterObj, totalCapital, totalLower);
    
    
        //Close files
        input.close();
        output.close();
    
    
        return 0;
    }
    
    
    void openFile(ifstream& inFile, ofstream& outFile)
    {
        string inFileName;
        string outFileName;
    
    
        cout << "Enter the name of the input file: ";
        cin >> inFileName;
        inFile.open(inFileName.c_str());
        cout << endl;
    
    
        cout << "Enter the name of the output file: ";
        cin >> outFileName;
        outFile.open(outFileName.c_str());
        cout << endl;
    }
    
    
    void count(ifstream& inFile, letterType letterList[], int& totalBig, int& totalSmall)
    {
        char ch;
    
    
        //Loop to initialize the array of structs; set letterCount to zero
        for(int index = 0; index < 26; index++)
        {
            //This segment sets the uppercase letters
            letterList[index].letter = static_cast<char>(65 + index);
            letterList[index].letterCount = 0;
    
    
            //This segment sets the lowercase letters
            letterList[index + 26].letter = static_cast<char>(97 + index);
            letterList[index + 26].letterCount = 0;
        }
    
    
        //read first character
        inFile >> ch;
    
    
        //Keep reading until end of file is reached
        while(!inFile.eof())
        {
            //If uppercase letter or lowercase letter is found, update data
            if('A' <= ch && ch <= 'Z')
            {
                letterList[static_cast<int>(ch) - 65].letterCount++;
                totalBig++;
            }
            else if('a' <= ch && ch <= 'z')
            {
                letterList[static_cast<int>(ch) - 71].letterCount++;
                totalSmall++;
            }
    
    
            //read the next character
            inFile >> ch;
    
    
        } //end while
    } //end function
    
    
    void printResult(ofstream& outFile, letterType letterList[], int totalBig, int totalSmall)
    {
        outFile << fixed << showpoint << setprecision(2);
        outFile << "Letter    Occurences     Percentage" << endl;
    
    
        for(int index = 0; index < 52; index++)
        {
            if(0 <= index && index <= 25)
            {
    
    
                outFile << setw(4) << letterList[index].letter << setw(12) << letterList[index].letterCount << " ";
                outFile << setw(15)<< 100 * (letterList[index].letterCount / (static_cast<float>(totalBig)+static_cast<float>(totalSmall))) << "%" << endl;
            }
            else
            {
                outFile << setw(4) << letterList[index].letter << setw(12) << letterList[index].letterCount << " ";
                outFile << setw(15) << 100 * (letterList[index].letterCount / (static_cast<float>(totalBig)+static_cast<float>(totalSmall))) << "%" << endl;
            }
        } //end for
    } //end
    
    
    void Info (ofstream& outputFile)
    {
    
    
        string outputFileName;
    
    
    
    
        cout << "Enter your name: ";
        cin >> outputFileName;
        outputFileName = outputFileName+"_p4.txt";
        outputFile.open(outputFileName.c_str());
    
    
        outputFile << "Programmer name: ";
        outputFile << "\nThis program is a collection of variable declarations";
        outputFile << "\nand function calls. This program reads a text and outputs";
        outputFile << "\nthe letters, together with their counts, as explained below";
        outputFile << "\nin the function printResult.";
        outputFile << "\n\nThe program consists of the following four functions:\n";
        outputFile << "\n**Function openFile: Opens the input and output files. You must pass the";
        outputFile << "\nfile streams as parameters (by reference, of course). If the file does not";
        outputFile << "\nexist, the program should print an appropriate message and exit. The";
        outputFile << "\nprogram must ask the user for the names of the input and output files.";
    
    
        outputFile << "\n\n**Function count: counts every occurrence of capital letters A-Z and";
        outputFile << "\nsmall letters a-z in the text file opened in the function openFile. This";
        outputFile << "\ninformation must go into an array of structures. The array must be passed";
        outputFile << "\nas a parameter, and the file identifier must also be passed as a parameter.";
    
    
        outputFile << "\n\n**Function printResult: Prints the number of capital letters and small";
        outputFile << "\nletters, as well as the percentage of capital letters for every letter A-Z and";
        outputFile << "\nthe percentage of small letters for every letter a-z. The percentages";
        outputFile << "\nshould look like this: ‘‘25%’’. This information must come from an array";
        outputFile << "\nof structures, and this array must be passed as a parameter.";
    
    
        outputFile << "\n\n**Function Info: Creates an output file named 'yourName_P4.txt'";
        outputFile << "\nthat contains all your required programmer info, along with";
        outputFile << "\nTA name,..) a description of the program ( what it does, and how),";
        outputFile << "\nand how you approached solving it. You must include your algorithm that";
        outputFile << "\nyou wrote, including the steps and any refinements made.";
        outputFile << "\nFor Project 5, create an output file named 'yourName_P5.txt.'";
    
    
        outputFile << "\n\n\n\n\n";
        cout << endl;
    }
    Last edited by bmess001; 11-26-2016 at 05:46 PM.

  2. #2
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    Simply change the struct to a class, make the existing members private, and add 2 public member functions that will allow to modify the private members.. depending on how you want to do it, you may add more than 2. Then, whenever you see ".member" in the code, change it to the respective function call to get or set the value..

    Just curious, but what happens if you pass in a file that has exactly 1 character in it (no newlines or anything afterwords.. just a 1 byte file)? I think you will find it doesnt work as expected..

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Just curious, but what happens if you pass in a file that has exactly 1 character in it (no newlines or anything afterwords.. just a 1 byte file)? I think you will find it doesnt work as expected..
    What makes you think it won't work with a single character?

    Jim

  4. #4
    Registered User
    Join Date
    Nov 2016
    Posts
    2
    I've tried things along the lines of what you're saying over and over again but I cant get it to run I am a beginner at this stuff.. I don't know exactly what the 2 public member functions should do. Also, when you say to change ".member" do you mean change the occurrences of ".letter" and ".letterCount" ??

    thanks for helping me out!

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Why don't you start with a simple program like
    Code:
    struct foo {
      int member;
    };
    int main ( ) {
      foo thing;
      thing.member = 1;
      cout << thing.member << endl;
    }
    Now try
    - make it a class
    - add public set/get methods
    - call thing.set() and thing.get() as appropriate.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Perhaps you need to review your textbook on classes?

    Perhaps this will help: Classes I.

    Start by just changing "struct" to "class" and add the access speicifiers ("public:, private:") and recompile. At this stage the class member variables should be in the public section. Once you verified that these changes are correct you can then start creating your class member functions. You will use your class member functions to allow access to the class member variables when you move them into the private section of the class. Remember when you move your class member variables to the private access section you will not be able to access those variables anywhere outside of the class, which means you will have to change your program everywhere you try to access the class member variables.
    I don't know exactly what the 2 public member functions should do.
    Your public member functions should allow you to set the value of one of the private member variables, and to return the value held in one of the private member functions. So start with something as simple as:

    Code:
    //class definition
    class letterType
    {
        private:
            char letter;
        public:
            int letterCount;
            void set_letter(char value);
            char get_letter();
    };
    
    void letterType::set_letter(char value)
    {
        letter = value;
    }
    
    char letterType::get_letter()
    {
        return(letter);
    }
    Now after making these changes you should compile your program. There should be several errors because the program can't access that private variable, so now you need to change the program to call your get or set functions instead of trying to access the variable directly.

    For example from your count function:
    Code:
        //Loop to initialize the array of structs; set letterCount to zero
        for(int index = 0; index < 26; index++)
        {
            //This segment sets the uppercase letters
            //letterList[index].letter = static_cast<char>(65 + index);   // This will fail to compile.
            letterList[index].set_letter(static_cast<char>(65 + index)); // So you now need to use the set function.
    ... 
       }
    You'll need to change the method of access everywhere in the program. And don't forget you'll also need to do the same type of changes when you want to "view" the value of the variable outside the class.

    Jim

  7. #7
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    Quote Originally Posted by jimblumberg View Post
    What makes you think it won't work with a single character?

    Jim
    Well the file reading logic is incorrect. Because EOF is a condition, not a character. After reading the first byte of a 1 byte file, EOF will be set to true and the main loop will not execute. Also, if the file is empty the file stream will enter a fail state and EOF should return true immediately with the same effect: the loop will not execute.. thus "eating" a character. It would be simpler to use

    Code:
    while (cin << input) { blah; blah; blah; }
    in a C++ program.

    I know because coding a reliable input processing system, even as simple as this, is not that straightforward unless you understand the error conditions that can occur while reading from the file.

    EDIT:

    Ok, say the input file is 1 byte. Then, after executing the code

    Code:
    char c;
    cin << c; // or whatever wierd C++ thing to read a byte from a file LOL
    The EOF condition will be set to true. And the main loop will not execute. Also, if the file is empty, the cin << inFile will set the input stream into a fail state, and should also set EOF, and the main loop will not execute either way.

    I will note that the cin and cout operators << and >> are highly non-intuitive and confusing because, despite using them hundreds of times in practice, I still know that my usage here is probably incorrect ... due to its non-intuitive nature.

    I mean really wouldn't it be

    Code:
    char c = '\0';
    c << cin;
    to read a byte?

    Or is it

    Code:
    cin >> c;
    Or is there really any sense at all to it.. not really.. just learn the definitions I suppose. I myself would highly prefer something like

    Code:
    char c = fgetch(stdin);
    which, I think, makes its pretty damn clear whats happening there...
    Last edited by MacNilly; 11-28-2016 at 06:57 AM.

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Well the file reading logic is incorrect.
    This is incorrect in this case, the logic is correct.
    Because EOF is a condition, not a character.
    This is correct, but the user is testing the stream state not a character so the usage is correct.
    After reading the first byte of a 1 byte file, EOF will be set to true and the main loop will not execute.
    This is false. You stated the file would have one and only one character so when the first character is read the eof() flag has not yet been set and that one and only one character is read into ch. The eof() flag will not be set until the read at the end of the loop, remember eof() is not set until after you try to read past the end of the file.

    Also, if the file is empty the file stream will enter a fail state and EOF should return true immediately
    The file stream will be placed into an error state after the read attempt prior to the while() loop therefore the while() loop will properly fail to run because the condition clause fails. However you did state in your statement that there was one and only one character in the file.

    Let's look at the code in question:
    Code:
        //read first character
        inFile >> ch;   // There is one character in the file, so eof() is false, ch contains that character.
     
     
        //Keep reading until end of file is reached
        while(!inFile.eof())
        {
            //If uppercase letter or lowercase letter is found, update data
            if('A' <= ch && ch <= 'Z')
            {
                letterList[static_cast<int>(ch) - 65].letterCount++;
                totalBig++;
            }
            else if('a' <= ch && ch <= 'z')
            {
                letterList[static_cast<int>(ch) - 71].letterCount++;
                totalSmall++;
            }
     
     
            //read the next character
            inFile >> ch;  // Because there is only one character this read will fail and set eof(), causing the while condition to fail on the next iteration.
     
     
        } //end while

    While using the actual read in the while() control statement is the preferred method of reading a file because it is simpler and less error prone using eof() to control a loop. But using eof(), when used properly as in this case, can be used to control a read loop.

    Or is there really any sense at all to it.. not really.. just learn the definitions I suppose.
    Remember that the arrows (>>) point the way of data transfer, cin >> ch get data from cin and place it in ch. cout << ch get data from ch and place it into the cout stream.
    I myself would highly prefer something like
    Code:
     char c = fgetch(stdin);
    But remember that fgetch() returns an int not a char. If you use a char you may not be able to detect EOF with that function.

    And when dealing with a char perhaps you would be more confortable with using "get()" instead:
    Code:
    int get();
    istream& get (char& c);

    Jim

  9. #9
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    Quote Originally Posted by jimblumberg View Post
    The eof() flag will not be set until the read at the end of the loop, remember eof() is not set until after you try to read past the end of the file.

    Remember that the arrows (>>) point the way of data transfer, cin >> ch get data from cin and place it in ch. cout << ch get data from ch and place it into the cout stream.

    But remember that fgetch() returns an int not a char. If you use a char you may not be able to detect EOF with that function.
    Jim
    Well... I stand elucidated.

    Of course.. how can the stream know if its end of file until you actually TRY to read.

    And the direction of the >> and << operators, I once knew.. but I still find it quite unintuitive, sorry.

    And yes, I was sloppy on the fget** functions returning int, not char.. my mistake.

    I guess there was no error after all in the file reading loop.

  10. #10
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    Yes, change the structure member accessor (dot notation) from a direct public field reference, to a public class method call.

    So you can have methods GetLetter() and GetLetterCount(). All these methods do is return the value of the private member, which can only be accessed through these public functions. Yes, I agree, it is a roundabout method and seems pointless but that's what a lot of professors are about these days.. data hiding. I think that's really all you need to do.

    Jimblumberg has posted the code you need, so I will bow out.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. So I wrote a class.
    By brewbuck in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 12-13-2008, 06:22 PM
  2. Can someone look over the program I wrote?
    By brooklyn in forum C++ Programming
    Replies: 10
    Last Post: 04-16-2006, 07:23 AM
  3. Change data format from CString to int
    By ooosawaddee3 in forum C++ Programming
    Replies: 5
    Last Post: 11-04-2002, 10:43 AM
  4. Qusetion on Class/Struct program
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 05-05-2002, 12:04 AM
  5. Can anyone change this into C format?
    By Wizard_D in forum C++ Programming
    Replies: 6
    Last Post: 12-19-2001, 08:49 AM

Tags for this Thread