Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Conversations: How to Persist an Object


July 2001 C++ Experts Forum/Conversations


It was 00:10 local Europa Base time when I slumped down the corridor. I was exhausted; three days of afternoon watch were getting to me.

A small beam of soft light spilled out across the cool metal corridor. It was coincidence, I think, that Major Gilb's door was slightly ajar, although the fact that the ventilation system had been suffering lately probably also had something to do with that. It was more coincidental that the Colonel was visiting the Major in the latter's office, instead of the reverse.

It was, on the other hand, certainly no coincidence that, when I heard low voices, I slowed down and listened. The sigh and hum of the ventilation made the listening more difficult, but it also concealed my presence.

"—me but that they're persistent mother's sons," the other voice, which I later found out to be the Colonel's, was saying.

There was a silence, and then Gilb's voice: "They're en route, then? How many? What's the ETA?"

"At least six ships." Pause. "Give 'em a month. It's imperative that the UN retain control of this installation until we can determine what technologies we're sitting on here. However long it takes."

There was what had to be Gilb's laughter. "The UN? You mean the Union."

"It's all the same. The Asians are persistent. We have to discourage them."


"Y'know, pardner, you've seemed a little distracted lately," Wendy said as she mixed her wasabi into the soy sauce, getting ready to dig into her sushi. "Everything all right?"

I concentrated on my California rolls for a minute. "It's Anna," I confessed. "Ever since I found out that she's Bob's daughter, I've been avoiding her. She calls me every once in a while, but I haven't been returning her calls. I deleted her phone number from my PDA. I like her, but I don't know if I can handle..."

"Anna was at my baby shower last weekend," Wendy nodded understandingly. "She really likes you." When I didn't answer, Wendy continued: "I'm going to tell you what I told her. When I first met my husband, I was working a lot of overtime. It was one of those companies that always seems to be in deadline mode, you know? Anyway, Tom kept asking me out, and I wanted to, but I always had to work. Finally, I decided to make time. And the rest, as they say, is history. Tom kept trying, and so I told Anna to keep trying. Persistence pays off."

"Agh! Don't talk to me about persistence!" I grumbled.

Wendy blinked. "Huh?"

"Oh," I shook my head, "I'm trying to implement some simple object persistence in my class hierarchy. I haven't been able to figure out how to do it. I asked the Guru for some help, but she said that she had taught me everything I need to know. I just can't figure it out."

Wendy pursed her lips in thought. "This one time I'll waive our agreement about no shop talk over lunch. Fill me in a little more."

"I know it's not that difficult," I said around a mouthful of rice. "Once I get going, I know I'll be fine. The main application can instantiate a derived class. I need to be able to write that class to an ostream. No problem. But I'm stuck on how to reconstitute the correct class when I read it back in."

"The Guru's right — you do know everything you need to know. How do you create an object, when you don't know the exact type of the object until run time?"

"Use a class factory," I said.

"Right, just like the one you implemented last month [2]. Now, what do you pass to the factory to get the appropriate type?"

"Some sort of token. I used a std::string."

"OK, now where do you get that token?"

"Ummm... well, it isn't going to appear out of thin air, so I guess I read it from the file." At that moment, the penny dropped. "Oh, of course. When I write out the object, first I write out the token indicating what type of object it is, and then I write the object's information. Reconstituting it is a simple matter of reading the token, passing it to the factory, and then streaming it in from the file."

"Right," Wendy replied. "And if you want to get really fancy, you can...."

"Hold it!" I signaled a time-out. "Thanks for helping me clear my mental log jam. Now that it's clear, I'm re-invoking the 'no-shop-talk' rule." I dug into the main course.

Later, when Wendy and I got back to the office, I sat at my computer and hammered out the base class fairly quickly:

class Base
{

private:
    // ... whatever data ...

    virtual std::string classID() const { return "Base"; }

protected:
    // Derived classes should call their parent's
    // implementation of this function after they 
    // load themselves.
    virtual void do_read( std::istream& );

    // Derived classes should call their parent's
    // implementation of this function after they 
    // save themselves.
    virtual void do_write( std::ostream& ) const;

public:
    // ... whatever virtual functions are required ... 

    // Streaming functions.
    void read( std::istream& );
    void write( std::ostream& ) const;

    virtual ~Base();
};

// Streaming helpers. Note that they are not friends!
std::ostream& operator <<
    ( std::ostream& o, const Base& b) { b.write(o); }
std::istream& operator >>
    ( std::istream& o, Base& b) { b.read(o); }
// <a href="#3">[3]</a>

"Very good, my child," I heard the Guru's voice behind me. As I jumped, I cursed at myself for not predicting her arrival. She continued: "Give me a quick walk-through of your writings."

"Simple enough," I said, as the Guru sat in the guest chair. "Base::write is called via the overloaded insertion operator. Here's its implementation:"

void Base::write( std::ostream& o ) const
{
    o << classID() << std::endl;
    do_write(o);
}

"Ah, the Template Method pattern," the Guru nodded. "Very wise, my child [4]."

"The implementation is fairly simple," I continued. "It simply writes out the class identifier and then invokes the do_write virtual function. do_write handles the gory details of writing the object's information to the stream. Each derived class must call its parent's do_write function. Reading is slightly more complicated, though." I called up the function I had written to encapsulate the reading:

std::auto_ptr<Base> loadBase( std::istream& inFile )
{
    std::string className;
    std::getline( inFile, className );

    std::auto_ptr<Base> newBase =
        genericFactory<Base>::instance().create(className);

    if( newBase.get() != 0 ) {
        inFile >> *newBase;
    }

    return newBase;
}

"It's a three-step process. First, I retrieve the class ID from the file. Then I use that identifier to get a new object from the class factory, and finally I reconstitute the class's data, via the read function:"

void Base::read( std::istream& i )
{
    do_read(i);
}

"I'm using the Template Method pattern here, too, but that's probably overkill for a simple function like this. do_read, of course, handles the gory details of reading in the information, validating it, and so on. Like the do_write function, a derived class's do_read should call its parent's do_read function."

"Well done, my child," the Guru said as she stood up.

"Before you go," I blurted out. The Guru paused. "Tell Anna I've lost her phone number, but I'll be home tonight if she wants to call me." The Guru nodded and glided away.


"'Discourage.' Ah." It was Gilb's voice again. I blinked and shook my head to clear away the tired haze. "What do they know?"

"Not much, we think. The Asians suspect something."

"They don't believe our cover story of communications problems that happen to cut off all of their nationals from talking with them?" Gilb's voice was openly sarcastic.

"They suspect," the other voice repeated. "And they're coming. We need to deal with it. What have your tech teams discovered so far?"

I was feeling increasingly uncomfortable standing in the corridor and didn't wait to hear more. There would be time enough after a good night's sleep.

Note from the Authors

Our thanks to Andrei Alexandrescu for pointing out a small, but significant, naming problem with our previous article. We incorrectly referred to the GoF ("Gang of Four") design pattern "Factory Method" as the "Abstract Factory" pattern. Each of these patterns has a chapter devoted to it, in Andrei's book Modern C++ Design (Addison-Wesley, 2001). We apologize for any confusion.

Notes

[1] Can be sung to the tune of "How to Handle a Woman" (Camelot, Lerner and Loewe).

[2] Jim Hyslop and Herb Sutter. "Conversations: A Factory, Template Style," C/C++ Users Journal C++ Experts Forum, June 2001, www.cuj.com/experts/1906/hyslop.htm.

[3] A full, working example program is available to download from hyslop.zip.

[4] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995).

Jim Hyslop is a senior software designer at Leitch Technology International Inc. He can be reached at [email protected].

Herb Sutter (www.gotw.ca) is secretary of the ISO/ANSI C++ standards committee and author of the acclaimed books Exceptional C++ and More Exceptional C++ (available summer 2001). Herb is also one of the featured instructors of The C++ Seminar (www.gotw.ca/cpp_seminar).


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.