-1

I would like to start this thread by thanking you for taking to the time to read my query.

I have created a function called retreiveFile which as you would expects retreives a file and reads from it. The text it reads is a set of numbers and text which represent names, cost and that sort of thing.

I have used istringstream to read through the file, determine the starting number(so I know what the line represents(property, card, ect)). Currently I have the file outputting the text but only with its corresponding data.

Example:

9 Oakmoor Road 80 5 0

9 Eldon Road 50 5 0

I need to know how I could pass this information into a class as I assume because I am going to have many objects of the same class I need to pass the data into main somehow. (I tried creating the class using constructor within the function but it would not work)

I am assuming I would have to create pointers for the information, pass it to main, create the constructors and then delete the pointers.

My question to you would be how could I do this efficiently as I need to create around 30 objects which could fit in several different types of classes as some have different parameters.

I'm sorry in advance in some information seems vague or confusing I am still, in my head, trying to picture how I could do it.

An example of one of the ways I've separated the text within the file so I can easily pass it over to its correct class.

if (word[i].find("1") == 0){ //starts with 1
        istringstream is(word[i]);
        string aword;
        
        int loopTimes = 0;
        while (is >> aword) {    // read each word from line
            string propertyArray[6];
            if (loopTimes == 0){
                string stringIdentificationNum = aword;
                /* const char * charIdentificationNum = stringIdentificationNum.c_str();
                int identificationNum = atoi(charIdentificationNum); */
                cout << "(1.1)" << aword;
                propertyArray[0] = aword;
            }
            else if (loopTimes == 1){
                cout << "(1.2)" << aword;
                propertyArray[1] = aword;
            }
            else if (loopTimes == 2){
                cout << "(1.3)" << aword;
                propertyArray[2] = aword;
            }
            else if (loopTimes == 3){
                cout << "(1.4)" << aword;
                propertyArray[3] = aword;
            }
            else if (loopTimes == 4){
                cout << "(1.5)" << aword;
                propertyArray[4] = aword;
            }
            else if (loopTimes == 5){
                cout << "(1.6)" << aword << endl;
                propertyArray[5] = aword;
            }
            loopTimes++;
            /* Property(propertyArray[0], propertyArray[1], propertyArray[2], propertyArray[3], propertyArray[4], propertyArray[5]); */
        }
    }

An example of the propertyClass

 class Property : public Card{
private:
    int identificationNum;
    string propertyName;
    int propertyCost;
    int propertyRent;
    int propertyColour;
public:
    //constructor
    Property::Property(int inputIdentificationNum, string inputFName, string inputSName, int inputCost, int inputPropertyRent, int inputPropertyColour){
        setIdentificationNum(inputIdentificationNum);
        setFirstName(inputFName, inputSName);
        setPropertyCost(inputCost);
        setPropertyRent(inputPropertyRent);
        setPropertyColour(inputPropertyColour);
        cout << "Property Created" << endl;
    }
    //set data
    void setIdentificationNum(int inputIdentificationNum){
        identificationNum = inputIdentificationNum;
    }
    void setFirstName(string inputFName, string inputSName){
        string nameCombined = inputFName + " " + inputSName;
        propertyName = nameCombined;
    }
    void setPropertyCost(int inputCost){
        propertyCost = inputCost;
    }
    void setPropertyRent(int inputPropertyRent){
        propertyRent = inputPropertyRent;
    }
    void setPropertyColour(int inputPropertyColour){
        propertyColour = inputPropertyColour;
    }
    //retreive data
    int getIdentificationNum() {
        return identificationNum;
    }
    string getName(){
        return propertyName;
    }
    int getPropertyCost(){
        return propertyCost;
    }
    int getPropertyRent(){
        return propertyRent;
    }
    int getPropertyColour(){
        return propertyColour;
    }
};

Thank you in advance for reading this thread.

Community
  • 1
  • 1
User5916261
  • 43
  • 1
  • 7
  • 2
    you're right, that is vague and confusing :P – Robin Hartland Feb 18 '16 at 17:40
  • 1
    It looks like you should [overload the stream operator](http://stackoverflow.com/questions/2351972/whats-the-right-way-to-overload-the-stream-operators-for-my-class) for your class and use that to read in the data. – NathanOliver Feb 18 '16 at 17:43
  • @NathanOliver Hi thank you for the reply. Would that allow me to dynamically create more than one class? – User5916261 Feb 18 '16 at 17:48
  • More than one class or more than one object? It would allow you to create as many objects of that class type as you want. – NathanOliver Feb 18 '16 at 17:49
  • @NathanOliver there are several types of classes which the file could be filtered in. The one above, any of the information from the file which goes into that code would be used to create an object of the property class. There are(going to be if I can get it working) many objects of a class and there are many classes. – User5916261 Feb 18 '16 at 17:53
  • off topic: `if (loopTimes == 0){` and subsequent `else`s is screaming for a `switch` – user4581301 Feb 18 '16 at 17:56
  • off topic: `string propertyArray[6];` is defined inside the body of the `while` loop. That means it is a local variable that only exists inside the body of the `while` loop. That also means it recreated every iteration of the while loop. So on `loopTimes == 3` the only valid value within `propertyArray` will be `propertyArray[3]`. All others will be empty. – user4581301 Feb 18 '16 at 18:01
  • `word[i].find("1") == 0` can be done without `find` `word[i][0] == "1"` will test if the first character of `word[i]` is `"1"` – user4581301 Feb 18 '16 at 18:04
  • @user4581301 Thanks for clearing that up. I'm sure I would of noticed where I placed the array had I of been able to pass it to the class. One problem at a time, thanks though – User5916261 Feb 18 '16 at 18:09
  • Thinking about it a bit more, that `while` loop can be gutted and spitted: `while (is >> aword) { cout << "(1." << looptimes + 1 << ")" << aword; propertyArray[looptimes] = aword; }` – user4581301 Feb 18 '16 at 18:10

1 Answers1

1

Passing pointers around is unnecessary for this task and is actually frowned on. An objects data should stay locked up and hidden in the object unless you have a really good reason to expose it. In this case OP doesn't.

What follows cleans up OP's code and fixes some of the problems that made their attempt unworkable and probably lead them down the road to over-complicating things further.

Example is a container for a list of properties. Rather than passing around pointers to to the properties, OP can pass around references to Example and read the properties from example. This allows Example to defend itself from its clients. With a pointer to a property, a client could mistakenly change change a value that could result in breaking Example or another client of Example. With a Getter method, Example can control access to the properties with whatever grain is required.

Example, in this case, allows everyone to see properties, so long as the property exists, but does not allow changing the property.

#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
class Example
{
private:
    static constexpr size_t MAX_PROPERTIES = 6;
    std::string propertyArray[MAX_PROPERTIES];

propertyArray is now a member variable and has scope that matches the object. Consider using a vector. It is not arbitrarily limited in size

public:
    Example(std::stringstream & is)
    {
        std::string aword;
        size_t looptimes = 0;
        while (is >> aword && looptimes < MAX_PROPERTIES)
        {
            std::cout << "(1." << looptimes + 1 << ")" << aword << std::endl;
            propertyArray[looptimes] = aword;
            looptimes++;

This is where making propertyArray a vector really helps. You can use the push_back method to keep adding more and more properties. If you have a case with 8 properties in the future, it uses the exact same code as the 8 property version and you don't have to guard against overflow with the && looptimes < 6 in the while

        }
    }

    std::string getProperty(size_t propertyNo)

New method used to get the properties for clients of Example. That way you don't have to pass around pointers to Example's data. Just pass around Example and if Example wants to give data, it can. No one can use an unprotected back door into Example to screw with Example's data without permission.

    {
        if (propertyNo < MAX_PROPERTIES)
        {
            return propertyArray[propertyNo];
        }
        throw std::out_of_range("Invalid property number");
    }
};

And to test it out...

int main()
{
    std::stringstream is ("A B C D E F G");
    Example test(is);
    try
    {
        std::cout << test.getProperty(4) << std::endl;
        std::cout << test.getProperty(6) << std::endl;
    }
    catch (std::out_of_range & exc)
    {
        std::cout << exc.what() << std::endl;
    }
}

Output:

(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
E
Invalid property number

And now with a std::vector:

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>

class Example
{
private:
    std::vector<std::string> propertyArray;

public:
    Example(std::stringstream & is)
    {
        std::string aword;
        while (is >> aword)
        {
            propertyArray.push_back(aword);
            std::cout << "(1." << propertyArray.size() << ")" << aword << std::endl;
        }
    }

    std::string getProperty(size_t propertyNo)
    {
        if (propertyNo < propertyArray.size())
        {
            return propertyArray[propertyNo];
        }
        throw std::out_of_range("Invalid property number");
    }
};

int main()
{
    std::stringstream is ("A B C D E F G");
    Example test(is);
    try
    {
        std::cout << test.getProperty(4) << std::endl;
        std::cout << test.getProperty(7) << std::endl;
    }
    catch (std::out_of_range & exc)
    {
        std::cout << exc.what() << std::endl;
    }
}

Output:

(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
(1.7)G
E
Invalid property number
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Hi thank you for your reply and I will try to implement what you have said to solve my problem. However the reason my logic and code is somewhat awful is because I am only using what I have been taught. I am still very much in the learning stage. To comment about protecting the class from a user I would like to mention that everything is going to be automated with no userinput – User5916261 Feb 18 '16 at 19:43
  • Thank you for pointing out some poor wording. To disambiguate, I'll edit and replace "user" with "client". I did not mean people interacting with `Example` I meant other program modules. – user4581301 Feb 18 '16 at 19:51