"Undefined Symbols" when inheriting from stdexcept classes

c++, debugging, exception, inheritance

Solution

There is a problem with the way you are catching your exceptions. Specifically, consider this code:

struct Base
{
    virtual void do() { std::cout << "Base!" << std::endl; }
};

struct Derived : Base
{
    virtual void do() { std::cout << "Derived!" << std::endl; }
};

void foo(Base x)
{
    x.do();
}

int main()
{
    Derived d;
    foo(d); // <--
}

On that marked line, `d` gets what is called "sliced". That is, in order to satisfy being a `Base`, everything that isn't part of `Base` gets sliced off! So the above code will output "Base!".

If we want the intended output, we need to make the parameter not a value:

void foo(Base& x) // polymorphic
{
    x.do();
}

Our above code would then display "Derived!", because it's no longer being sliced. (One could also use a pointer.)

So, take a look at your catch clause:

catch (exception e)

Here, any exceptions you've thrown will be sliced into the base `std::exception` class, losing any derived information! This is why it's much more common (and possibly "correct") to catch-by-reference:

catch (const exception& e)

You'll now find `e.what()` returns the non-sliced error message, as intended.

Old

Here's how the entire thing should look (don't use `using namespace` in a header!):

// rpn_expression_error.h
#include <stdexcept> // for logic_error
#include <string> // for string

class rpn_expression_error : public std::logic_error
{
public:
    explicit rpn_expression_error(const std::string& pMsg);
};

// rpn_expression_error.cpp
#include "rpn_expression_error.h"

rpn_expression_error::rpn_expression_error(const std::string& pMsg) :
std::logic_error(pMsg)
{}

Older

Because those exception classes are declared inside the standard namespace, but yours is not. `string` is inside the namespace `std` so they don't need to qualify it, but you do:

#include <string>

// ...
                                    vvv 
explicit rpn_expression_error(const std::string& arg);

Keep in mind I've changed your parameter name. Names that contain a double-underscore are reserved, and you shouldn't use them.

Problem

Here is an exception defined in `<stdexcept>`: ``` class length_error : public logic_error { public: explicit length_error(const string& __arg); }; ``` Here is my exception: ``` #include <string> #include <stdexcept> using namespace std; class rpn_expression_error : public logic_error { public: explicit rpn_expression_error(const string& __arg); }; ``` Why do I get this error when `<stdexcept>` does not? ``` Undefined symbols: rpn_expression_error::rpn_expression_error(/*string*/ const&), referenced from: ... ld: symbol(s) not found ``` At @sbi's request, here is a minimal example of my code at the moment: ``` #include <string> #include <iostream> #include <stdexcept> using namespace std; class RPN_Calculator { public: class rpn_expression_error : public logic_error { public: explicit rpn_expression_error(const string& arg) : logic_error(arg) {} }; void Execute() { throw rpn_expression_error("Hello"); } }; int main() { RPN_Calculator calc; try { calc.Execute(); } catch (exception e) { cout << e.what() << endl; } } ``` I saved this as `rpn.cpp` and ran `make rpn`to produce the error. The code now builds completely, however, the real program still gives me the original error. Note/Solution: Although the code above runs just fine, the same exception class in the real code still produces the linker error. To simplify, I just promoted `rpn_expression_error` to its own global-scope class, and that seems to have fixed the problem.

Original source