Main Content

Reading files, and using factories to create vectors of objects from the data in C++

Archive - Originally posted on "The Horse's Mouth" - 2012-07-21 13:19:21 - Graham Ellis

On our C++ courses, we concentrate on objects and object design. But we also take a wider look at topics such as references and templates that go to making the complete language, with sections covering changes to things like file handling from the underlying C language.

I've just added a new example to our web site, developed during the last few days as a "show you how" on our course.

Scenario ... I have a file which comprises a number of records, and I want to read each of those records in, in turn, turn each into an object which I can then manipulate. This may be a very familiar scenario for anyone who's used to processing data.

The first sample program - [here] - uses a static C++ method (using a factory design pattern) to handle the data flowing in from the file. The factory method is rather like a utility function that resides in the class for the object type we're creating (in this case a Train). It contains code that's logically associated with setting up Trains (such as reaidng standard file formats of Train information), but it doesn't run on any pre-existing Train objects. And - although it may return a Train object (in the way a constructor always does, it may not ... our example returns a NULL if there's no (more) data available.

Here's the factory:

  Train* Train::factory() {
    char trainline[256];
    if (! datasource) { // Only on the first call do you open the file
      datasource = new ifstream("trains.txt");
      }
    // read the (next) line from the file
    datasource->getline(trainline,256);
    if (datasource->eof()) {
      return NULL;
      }
    return new Train(trainline);
    }


We're passing a complete (String) record to the constructor, you'll notice. For in this case, we can be sure that every string represents a good record. Within the constructror, we're separating out the individual fields in our space delimied line ... dropping %body% (null) characters in to conveniently split the string, then sucking out the various pieces we want:

  Train::Train(char * source) {
    int starts[4];
    int k=0;
    int param=0;
  
    while (source[k] != '%body%') {
      if (source[k] == ' ') {
        source[k] = '%body%';
        starts[param++] = k+1;
      }
      k++;
      if (param > 3) break;
    }
  
    this->ncars = atoi(&source[starts[2]]);
    this->spv = atoi(&source[starts[1]]);
    }





In the first example, we've only allowed for a specific and limited number of Train objects in the array in our main program. But it's rarely the case that we know how may are needed, so we've switched on to using a vector in the second example - see [here].

A vector is a collection (a linked list) which unlike an array doesn't need to occupy sequential memory locations - so it can be expanded later. In fact, we start off with it being zero in size (capacity):
  vector<Train *> *service = new vector<Train *>(0);

We can add Train object onto the end of it using the push_back method:
  service->push_back(current);

and we can then reference elements that we need using the at method:
  cout << service->at(k)->getcapacity() << endl;




In our final example, we've switched so that the program runs on data that's brought in from a file named on the command line. That final example is [here].

As there's more chance of the user getting things wrong, we've added in checks for command line usage:
  if (argc != 2) {
    cerr << "Usage: " << argv[0] << " filename" << endl;
    return 1;
    }

and we're also checking that our file open is working properly:
  datasource = new ifstream(source);
    if (! datasource->good()) {
      cerr << "Unable to open data file" << endl;
      return NULL;
      }


The data file that I used in running / testing these programs is [here]

We offer a range of C and C++ courses, suitable for the newcomer to programming (the longer courses) and the programmer converting to a new language (shorter ones). See C and C++ course details.