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

Polymorphic Exceptions


April, 2005: Polymorphic Exceptions

Herb Sutter (http://www.gotw.ca/) chairs the ISO C++ Standards committee and is an architect in Microsoft's Developer Division. His most recent books are Exceptional C++ Style and C++ Coding Standards (Addison-Wesley). Jim Hyslop is a senior software designer for Leitch Technology International. He can be reached at jhyslop@ ieee.org.


Frack!" I muttered. "Cylons gobbling your code again, pardner?" Wendy muttered back, over the cubicle wall.

"Ah, well, sorta," I sat back and stretched. "Got a second?"

"Sure," Wendy plunked herself in my guest chair. "'Sup?"

"Well, I'm trying to design this library," I tapped on the screen, "so that if it needs to throw an exception, the library users can pass in the type of exception they want thrown. All the exceptions are derived from a common base class. Problem is, the only exception I catch is the base class."

"Hmmm..." Wendy leaned in to examine the code.

#include <iostream>
#include <exception>

using namespace std;

class MyExceptionBase : public exception
{
};

class MyExceptionDerived : 
    public MyExceptionBase
{
};

void throwit( MyExceptionBase & e )
{
  throw e;
}

void dothrow( MyExceptionBase & e )
{
  try {
    throwit( e );
  } catch( MyExceptionDerived & me )
  {
    cout << "Caught derived\n";
  }
  catch ( MyExceptionBase & me )
  {
    cout << "Caught base\n";
  }
}

int main()
{
  MyExceptionBase base;
  MyExceptionDerived derived;
  dothrow( base );
  dothrow( derived );
}

"Well, let's see what happens if you move the logic from the dothrow function into main," Wendy said as she adjusted the code:

int main()
{
  MyExceptionBase base;
  MyExceptionDerived derived;
  try {
    throwit( base );
  } catch( MyExceptionDerived & me )
  {
    cout << "Caught derived\n";
  }
  catch ( MyExceptionBase & me )
  {
    cout << "Caught base\n";
  }

  try {
    throwit( derived );
  } catch( MyExceptionDerived & me )
  {
    cout << "Caught derived\n";
  }
  catch ( MyExceptionBase & me )
  {
    cout << "Caught base\n";
  }
}

She compiled and ran the code. The output was the same: "Caught base" times two.

"Didn't help," I volunteered. "Aw, let's see what the Standard says," I slid the keyboard over and called up the Holy...er, that is, the Standard. "Ah, here it is:"

A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw. [1]

"Static type!?!? Frack!" I repeated. "No wonder it's not working." I sighed. "Okay, now what?" Wendy and I stared at the code.

"Delegate," a voice whispered in my ear. I jumped, half expecting to see Tricia Helfer standing there. It was the Guru. I was just getting used to the Guru snapping a book to get our attention. Now she was changing her tactics!

"Gah...er, I mean, delegate?"

"Yes, my child," the Guru straightened up, as Wendy returned to her cubicle. "It is clear that your throwit function cannot pass the dynamic type of the object to the throw expression. But there is something in throwit that knows the dynamic type, and can therefore pass it to the throw expression."

"Oh!" I exclaimed. "Sure, easy enough. I'll just put in a series of if/else clauses based on its typeid, and use a dynamic_cast on it to cast it to the proper type. Like this," I quickly modified the function:

void throwit( MyExceptionBase & e )
{
  if ( typeid( e ) == 
    typeid( MyExceptionDerived ) )
  {
    throw dynamic_cast< 
      MyExceptionDerived &>( e );
  }
  throw e;
}
"That oughta do it," I fired up the compiler, then ran the program:
     Caught base
     Caught derived

"Yipee, that's got it, thanks." I looked up at the Guru. She did not share my enthusiasm.

"My apprentice, you seem to have forgotten something. When you take action based on the type of an object, that means..."

"Ummm...oh, right. That's precisely why polymorphism was inven...oh, I get it now. I need a virtual function in MyExceptionBase." I backed out my changes, and modified the classes:

class MyExceptionBase : public exception
{
public:
  virtual void Throw()
  {
    throw *this;
  }
};

class MyExceptionDerived :
    public MyExceptionBase
{
public:
  virtual void Throw()
  {
    throw *this;
  }
};

void throwit( MyExceptionBase & e )
{
  e.Throw();
}

"Much better, my young apprentice," the Guru smiled. "And yet, is there another way you can have the user set the rules?"

"Rules?" I asked.

"As in policies," Wendy prompted over the cubicle wall.

"Policies?" I asked.

"Yes, my apprentice," the Guru replied, "can this be done using a policy instead?"

"Uh, I think so," I turned back to the keyboard.

class MyException1 : public exception
{
public:
  void Throw()
  {
    throw *this;
  }
};

class MyException2 : public exception
{
public:
  void Throw()
  {
    throw *this;
  }
};

template < class ExceptionType >
void throwit( ExceptionType & e )
{
  e.Throw();
}

template< class ExceptionType >
void dothrow( ExceptionType & e )
{
[... same implementation as before]

I compiled and ran the program. It worked perfectly. "Kewl," I said. "Now I don't have to force everybody to derive their class from my own."

"Yes, my child, policy-based programming provides you with much flexibility and power." She turned and glided away.

References and Further Reading

  1. [1] ISO/IEC 14882:2003(E), "Programming Languages—C++," 15.1 63 and "How do I throw polymorphically?" C++ FAQ Lite, http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10.


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.