Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Inheriting from STL containers

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):

file.write();
 

The bulk of the program is involved with modifying the file in memory.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire