1

I've run across a coding problem that I'm having trouble understanding (note the line tagged with //-):

#include <iostream>

using namespace std;

class X { };

class X0 { };
class X1: public X0 { };
class X2: public X1 { };

void f(int i) {
    if (i == 0) {
        throw X0();
    } else if (i == 1) {
        throw X1();
    } else if (i == 2) {
        throw X2();
    } else {
        throw X();
    }
}

int main(int argc, char* argv[]) {
    try { 
        f(0);                      //-
    } catch (X1) {
        cout << "A" << endl;
    } catch (X2) {
        cout << "B" << endl;
    } catch (X0) {
        cout << "C" << endl;
    } catch (...) {
        cout << "D" << endl;
    }
}

The output of this code is C, as expected. If I change the tagged line to "f(1);" the output is A, also as expected.

However, if I change the tagged line to "f(2);" the answer is also A, and I'm not understanding why. I feel like it may have something to do with the scope of the destructors, but my attempts to find information on it haven't been successful because I'm not entirely sure what to study. Would anyone be able to explain what is happening here, or just the name of concept this problem is illustrating so I can research it? Any help is appreciated.

4
  • 2
    An X2 is also an X1, and the catch for X1 is first so it triggers. Commented Feb 7, 2017 at 1:29
  • 1
    What destructors? There are no destructors here. Commented Feb 7, 2017 at 1:31
  • 1
    And what do you mean by 'scope of the destructors'? Commented Feb 7, 2017 at 1:55
  • I was mistaken, this isn't a destructor problem. Commented Feb 7, 2017 at 2:03

5 Answers 5

3

An X2 inherits from X1 and so "is" an X1, and the catch block for X1 is first so triggers before we reach the X2 one.

Sign up to request clarification or add additional context in comments.

3 Comments

Oh, I see, so this is an Inheritance demonstration?
@Mock Exactly, this is why I always say inheritance is (generally) an "is" relationship. In almost every case if B is a child of A the code will act as if a B "is" and A and treat it as one if one is needed.
Okay, that makes sense, it's been a very long time since I've studied inheritance. Thank you for the help everyone, I'll approve this when possible.
3

When i == 2 , you throw an X2, X2 is derived from X1.

The order of catches matter, you attempt to catch X1 first, X2 (what you threw) is an X1, so that is the catch that fires. You need to reorder your catches to catch the most specific first

Comments

2

However, if I change the tagged line to "f(2);" the answer is also A, and I'm not understanding why.

This is because X2 is subclass of X1.

When you call f(2) in try, f(2) throws X2. It seems like the exception should be caught in catch(X2). However, X2 is subclass of X1.

So the exception is caught in catch(X1) and the code inside catch prints A.

So if you want to see B when you call f(2), the code should be like this.

//skipped some code

int main(int argc, char* argv[]) {
    try { 
        f(2);                      //-
    } catch (X2) {
        cout << "B" << endl;
    } catch (X1) {
        cout << "A" << endl;
    } catch (X0) {
        cout << "C" << endl;
    } catch (...) {
        cout << "D" << endl;
    }
}

Comments

1

You should catch X2 before X1, as it is derived from X1, otherwise the catch for X1 catches X2 as well.

In Java this would have been a compilation error.

Comments

1

The type of exception is matched in the order of catch clauses under the matching rules (http://en.cppreference.com/w/cpp/language/try_catch):

  • T is an unambiguous public base class of E

X1 is public base class of X2 so it's a match.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.