Home arrow C++ arrow Page 3 - Manipulating Streams and Files with C++
C++

Manipulating Streams and Files with C++


In this second part of a five-part series on handling streams and files in C++, you will learn how to format floating-point output, how to write your own stream manipulators, and more. This article is excerpted from chapter 10 of the C++ Cookbook, written by Ryan Stephens, Christopher Diggins, Jonathan Turkanis and Jeff Cogswell (O'Reilly; ISBN: 0596007612). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Author Info:
By: O'Reilly Media
Rating: 5 stars5 stars5 stars5 stars5 stars / 1
October 23, 2008
TABLE OF CONTENTS:
  1. · Manipulating Streams and Files with C++
  2. · 10.3 Writing Your Own Stream Manipulators
  3. · 10.4 Making a Class Writable to a Stream
  4. · 10.5 Making a Class Readable from a Stream

print this article
SEARCH DEVARTICLES

TOOLS YOU CAN USE

advertisement
Manipulating Streams and Files with C++ - 10.4 Making a Class Writable to a Stream
(Page 3 of 4 )

Problem

You have to write a class to an output stream, either for human readability or persistent storage, i.e., serialization.

Making a Class Writable to a Stream

Solution

Overload operator<< to write the appropriate data members to the stream. Example 10-6 shows how.

Example 10-6. Writing objects to a stream

#include <iostream>
#include <string>

using namespace std;

class Employer {
  friend ostream& operator<<              // This has to be a friend
    (ostream& out, const Employer& empr); // so it can access non- public:                                   // public members
   Employer() {}
  ~Employer() {}

  void setName(const string& name) {name_ = name;}
private:
  string name_;
};

class Employee {
   friend ostream& operator<<
     (ostream& out, const Employee& obj); public:
   Employee() : empr_(NULL) {}
  ~Employee() {if (empr_) delete empr_;}

  void setFirstName(const string& name) {firstName_ = name;}
  void setLastName(const string& name) {lastName_ = name;}
  void setEmployer(Employer& empr) {empr_ = &empr;}
  const Employer* getEmployer() const {return(empr_);}

private:
   string firstName_;
   string lastName_;
   Employer* empr_;
};

// Allow us to send Employer objects to an ostream...
ostream& operator<<(ostream& out, const Employer& empr) {

   out << empr.name_ << endl;

   return(out);
}

// Allow us to send Employee objects to an ostream...
ostream& operator<<(ostream& out, const Employee& emp) {
   out << emp.firstName_ << endl;
  
out << emp.lastName_ << endl;
  
if (emp.empr_)
    
out << *emp.empr_ << endl;

   return(out);
}

int main() {

   Employee emp;
  
string first = "William";
  
string last = "Shatner";
  
Employer empr;
  
string name = "Enterprise";
  
empr.setName(name);

   emp.setFirstName(first);
  
emp.setLastName(last);
  
emp.setEmployer(empr);

   cout << emp; // Write to the stream
}

Discussion

The first thing you need to do is declare operator<< as a friend of the class you want to write to a stream. You should use operator<< instead of a member function like writeToStream(ostream& os) because the left-shift operator is the convention for writing everything else in the standard library to a stream. You need to declare it as a friend because, in most cases, you want to write private members to the stream, and non-friend functions can't access them.

After that, define the version of operator<< that operates on an ostream or wostream (defined in <ostream>) and your class that you have already declared as a friend. This is where you have to decide which data members should be written to the stream. Typically, you will want to write all data members to the stream, as I did in Example 10-6:

  out << emp.firstName_ << endl;
 
out << emp.lastName_ << endl;

In Example 10-6, I wrote the object pointed to by empr_ by invoking operator<< on it:

  if (emp.empr_)
     out << *emp.empr_ << endl;

I can do this because empr_ points to an object of the Employer class, and, like Employee, I have defined operator<< for it.

When you are done writing your class's members to the stream, your operator<< must return the stream it was passed. You need to do this whenever you overload operator<<, so it can be used in succession, like this:

  cout << "Here's my object: " << myObj << '\n';

The approach I give is simple, and when you want to be able to write a class to an output stream for human consumption, it will work just fine, but that's only part of the story. If you are writing an object to a stream, it's usually for one of two reasons. Either that stream goes somewhere that will be read by a person (cout, console window, a log file, etc.), or the stream is a temporary or persistent storage medium (a stringstream, a network connection, a file, etc.), and you plan on reassembling the object from that stream in the future. If you need to recreate the object from a stream (the subject of Recipe 10.5), you need to think carefully about your class relationships.

Implementing serialization for anything other than trivial classes is hard work. If your class references (via pointer or reference) other classes--as most nontrivial classes do--you have to accommodate the potential for circular references in a meaningful way when writing out objects, and you have to reconstruct references correctly when reading them in. If you have to build something from scratch, then you'll have to handle these design considerations, but if you can use an external library, you should try the Boost Serialization library, which provides a framework for serializing objects in a portable way.

See Also

Recipe 10.5


blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 



© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 2 - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials