Exceptions and inheritance

N

Noah Roberts

I am a bit confused about how inheritance works with regard to
exceptions apparently.

class ParentEx : public std::exception
{
};

class SubEx : public ParentEx,std::runtime_error
{
};

SubEx is getting caught by catching ParentEx or SubEx, but not
std::exception.

Why?

Thanks.
 
P

Pete Becker

Noah said:
I am a bit confused about how inheritance works with regard to
exceptions apparently.

class ParentEx : public std::exception
{
};

class SubEx : public ParentEx,std::runtime_error
{
};

SubEx is getting caught by catching ParentEx or SubEx, but not
std::exception.

Why?

Because std::exception is an ambiguous base. There are two of them.
 
N

Noah Roberts

Pete said:
Because std::exception is an ambiguous base. There are two of them.

Is there two in the headers or because I am using multiple inheritance
and both parents derive from that class?
 
R

red floyd

Noah said:
Pete Becker wrote:




Is there two in the headers or because I am using multiple inheritance
and both parents derive from that class?

The latter. When you try to catch std::exception&, the compiler doesn't
know if you want to catch ParentEx's std::exception base or SubEx's
std::runtime_error base.
 
S

Shezan Baig

Noah said:
Is there two in the headers or because I am using multiple inheritance
and both parents derive from that class?
It is because of the multiple inheritance.

Hope this helps,
-shez-
 
N

Noah Roberts

Shezan said:
Noah Roberts wrote:
It is because of the multiple inheritance.


Figured. I still never quite get MI. Sometimes I really wish C++ did
the interface or protocol thing.

How would I set this kind of situation up then? I want all of these
exceptions to be considered as ParentExceptions, which needs to look
like an exception, but I also want to qualify some of them to say, "Well
this is a range_error, this is an xxx_error...That way the catch can be
either specific to the class, or more general in terms of stdlib.

Can that even be done or do I need to stop being silly?
 
D

Dave Moore

Noah Roberts said:
Figured. I still never quite get MI. Sometimes I really wish C++ did
the interface or protocol thing.

How would I set this kind of situation up then? I want all of these
exceptions to be considered as ParentExceptions, which needs to look
like an exception, but I also want to qualify some of them to say, "Well
this is a range_error, this is an xxx_error...That way the catch can be
either specific to the class, or more general in terms of stdlib.

Can that even be done or do I need to stop being silly?

Well, why are you deriving ParentEx from std::exception in the first place?
Presumably you have some message passing mechanics implemented (or at least
specified) in ParentEx that you want to be common to all of your SubEx
classes, so it makes sense to have it as a base class, but does it have to
be derived from std::exception? Consider:

class ParentEx {};

class DefaultEx : public ParentEx, public std::exception {};
class SubEx : public ParentEx, public std::runtime_error {};

Now you can throw DefaultEx when you don't need anything special, and all of
your objects will have exactly one std::exception base object in the
hierarchy.

However, I am not sure what you are trying to do here? Typically I either
derive from my own exception classes, or from the std ones, but I have never
found the need to do both. It seems to me that it might cause ambiguities
when trying to handle the exceptions further down the line.

HTH,

Dave Moore
 
N

Noah Roberts

Dave said:
Well, why are you deriving ParentEx from std::exception in the first
place?

Pretty much just to be sure that any subclass can be caught as
std::exception instead of having to rely on catch (...).

It could be a problem of me trying to be too general case...
 
N

Noah Roberts

Dave Moore wrote:
but does it have to
be derived from std::exception? Consider:

class ParentEx {};

class DefaultEx : public ParentEx, public std::exception {};
class SubEx : public ParentEx, public std::runtime_error {};

Ok, what kind of bogus crap would happen if ParentEx looked like this:

class ParentEx {
public:
virtual const char* what() const throw() {}
};
 
N

Noah Roberts

Dave said:
class ParentEx {};

class DefaultEx : public ParentEx, public std::exception {};
class SubEx : public ParentEx, public std::runtime_error {};

Ok, I didn't realize public had to be said both times. I thought
public qualified all base classes after. The problem is fixed now, it
passes all tests.
 
D

Dave Moore

Noah Roberts said:
Dave Moore wrote:
but does it have to

Ok, what kind of bogus crap would happen if ParentEx looked like this:

class ParentEx {
public:
virtual const char* what() const throw() {}
};

Hmm .. I am not completely sure (I also am not so familiar with MI), but I
think it would be ok, provided that you declare (and define) a what()
function in all derived classes (DefaultEx, SubEx). Otherwise the compiler
will (should) give an ambiguity error, because it cannot decide between
std::exception::what and ParentEx::what.

So again I ask, are you sure you need to use multiple inheritance here?

HTH,

Dave Moore
 
N

Noah Roberts

Dave said:
class ParentEx {};

class DefaultEx : public ParentEx, public std::exception {};
class SubEx : public ParentEx, public std::runtime_error {};

Ok, I did that. It still isn't working:

try
{
Date date("INVALID"); // Throws InvalidDateStringEx
fail_("Not thrown");
}
catch (std::exception e)
{
succeed_();
}
catch (...)
{
fail_("Not a std::exception.");
}

result of test run:
8DateTest failure: (Not a std::exception.) , DateTest.cpp (line 141)
Test "8DateTest":
Passed: 42 Failed: 1

The exceptions look like:

class DateException
{
// Derived classes should also inherit from std::exception.
};
class InvalidDateStringException : public
Date::DateException,std::runtime_error // string parse error.
{
public:
InvalidDateStringException(const std::string& msg = "") :
std::runtime_error(msg) {}
};

All other exception tests work, it registers as itself and
Date::DateException but not std::exception.
 
J

Jerry Coffin

Noah Roberts wrote:

[ ... ]
Figured. I still never quite get MI. Sometimes I really wish C++
did the interface or protocol thing.

MI is simply a generalized form -- it lets you do interfaces and
protocols, and a number of other things as well when needed.
How would I set this kind of situation up then? I want all of these
exceptions to be considered as ParentExceptions, which needs to look
like an exception, but I also want to qualify some of them to say,
"Well this is a range_error, this is an xxx_error...That way the
catch can be either specific to the class, or more general in terms
of stdlib.

At least at first blush, this sounds like you want std::exception as
the ultimate base class. You'll then derive your ParentException from
that, and the others from there.

I'm not entirely sure I've correctly interpreted what you've said
though.

Exceptions are _rarely_ a good time to use MI -- exceptions generally
seem to work best as a big more or less monolithic hierarchy.

I can concieve of one possibility though: assume you have a big program
in an existing framework (e.g. MFC) that already has its own exception
handling, its own exception hierarchy, etc. You want to migrate to the
std::exception hierarchy without doing wholesale modifications on your
large body of working code. At the same time, you need to be able to
throw an exception that can be caught by an existing handler that
expects something derived from CExecption, or by a new handler that
expects something derived from std::exception.

In this case, it might be reasonable to build a shadow hierarchy (so to
speek) that unifies the two. An example might be something like:

class you::range_error : public std::range_error, public
CRangeException {
// ...
};

and if your code throws one of these, it can be caught and viewed as
either an std::range_error, OR a CRangeException, whichever sort of
handler is found first.

This, however, looks to be like it has the potential for getting ugly
pretty quickly, and I hasten to point out that I'm _not_ particularly
recommending it as a good technique -- just pointing out a situation
where I can imagine that multiple inheritance and exceptions _might_
mix in a way that isn't immediately problematic.
 
J

Jerry Coffin

Noah Roberts wrote:

[ ... ]
Figured. I still never quite get MI. Sometimes I really wish C++
did the interface or protocol thing.

MI is simply a generalized form -- it lets you do interfaces and
protocols, and a number of other things as well when needed.
How would I set this kind of situation up then? I want all of these
exceptions to be considered as ParentExceptions, which needs to look
like an exception, but I also want to qualify some of them to say,
"Well this is a range_error, this is an xxx_error...That way the
catch can be either specific to the class, or more general in terms
of stdlib.

At least at first blush, this sounds like you want std::exception as
the ultimate base class. You'll then derive your ParentException from
that, and the others from there.

I'm not entirely sure I've correctly interpreted what you've said
though.

Exceptions are _rarely_ a good time to use MI -- exceptions generally
seem to work best as a big more or less monolithic hierarchy.

I can concieve of one possibility though: assume you have a big program
in an existing framework (e.g. MFC) that already has its own exception
handling, its own exception hierarchy, etc. You want to migrate to the
std::exception hierarchy without doing wholesale modifications on your
large body of working code. At the same time, you need to be able to
throw an exception that can be caught by an existing handler that
expects something derived from CExecption, or by a new handler that
expects something derived from std::exception.

In this case, it might be reasonable to build a shadow hierarchy (so to
speek) that unifies the two. An example might be something like:

class you::range_error : public std::range_error, public
CRangeException {
// ...
};

and if your code throws one of these, it can be caught and viewed as
either an std::range_error, OR a CRangeException, whichever sort of
handler is found first.

This, however, looks to be like it has the potential for getting ugly
pretty quickly, and I hasten to point out that I'm _not_ particularly
recommending it as a good technique -- just pointing out a situation
where I can imagine that multiple inheritance and exceptions _might_
mix in a way that isn't immediately problematic.
 
D

Dave Moore

[snip]
class InvalidDateStringException : public
Date::DateException,std::runtime_error // string parse error.
{
public:
InvalidDateStringException(const std::string& msg = "") :
std::runtime_error(msg) {}
};

All other exception tests work, it registers as itself and
Date::DateException but not std::exception.


looks like you forgot to specify "public" again in the specifications of the
base classes for InvalidDateStringException .. or is that just a posting
transcription error?

Dave Moore
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,201
Messages
2,571,048
Members
47,647
Latest member
NelleMacy9

Latest Threads

Top