Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
The power of instantly creating a sequence of elements is
amazing, and it makes you realize how much time you may have lost in the past
solving this particular problem. For example, many utility programs involve
reading a file into memory, modifying the file, and writing it back out to
disk. You might as well take the functionality in StringVector.cpp and
package it into a class for later reuse.
Now the question is: do you create a member object of type vector,
or do you inherit? A general object-oriented design guideline is to prefer
composition (member objects) over inheritance, but the standard algorithms
expect sequences that implement a particular interface, so inheritance is often
necessary.
//: C07:FileEditor.h
// A file editor tool.
#ifndef FILEEDITOR_H
#define FILEEDITOR_H
#include <iostream>
#include <string>
#include <vector>
class FileEditor : public
std::vector<std::string> {
public:
void open(const char* filename);
FileEditor(const char* filename) { open(filename); }
FileEditor() {};
void write(std::ostream& out = std::cout);
};
#endif // FILEEDITOR_H ///:~
The constructor opens the file and reads it into the FileEditor,
and write( ) puts the vector of string onto any ostream.
Notice in write( ) that you can have a default argument for the
reference.
The implementation is quite simple:
//: C07:FileEditor.cpp {O}
#include "FileEditor.h"
#include <fstream>
#include "../require.h"
using namespace std;
void FileEditor::open(const char* filename) {
ifstream in(filename);
assure(in, filename);
string line;
while(getline(in, line))
push_back(line);
}
// Could also use copy() here:
void FileEditor::write(ostream& out) {
for(iterator w = begin(); w != end(); w++)
out << *w << endl;
} ///:~
The functions from StringVector.cpp are simply
repackaged. Often this is the way classes evolve you start by creating a program
to solve a particular application and then discover some commonly used
functionality within the program that can be turned into a class.
The line-numbering program can now be rewritten using FileEditor:
//: C07:FEditTest.cpp
//{L} FileEditor
// Test the FileEditor tool.
#include <sstream>
#include "FileEditor.h"
#include "../require.h"
using namespace std;
int main(int argc, char* argv[]) {
FileEditor file;
if(argc > 1) {
file.open(argv[1]);
} else {
file.open("FEditTest.cpp");
}
// Do something to the lines...
int i = 1;
FileEditor::iterator w = file.begin();
while(w != file.end()) {
ostringstream ss;
ss << i++;
*w = ss.str() + ": " + *w;
++w;
}
// Now send them to cout:
file.write();
} ///:~
Now the operation of reading the file is in the constructor:
FileEditor file(argv[1]);
(or in the open( ) member function), and writing
happens in the single line (which defaults to sending the output to cout):
The bulk of the program is involved with modifying the file
in memory.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |