"Undefined Symbols" when inheriting from stdexcept classes
Here is the 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 am I getting this error if <stdexcept> not working?
Undefined symbols: rpn_expression_error::rpn_expression_error(/*string*/ const&), referenced from: ... ld: symbol(s) not found In the @sbi request, here is the 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 create an error .
Now the code is complete, however the real program still gives me the original error.
Note / Solution: Although the code above works very well, the same class of exceptions in real code still generates a linker error. To simplify, I just pushed rpn_expression_error into my own global scope class and seems to fix the problem.
There is a problem with how you take advantage of your exceptions. In particular, 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 this marked line, d gets the so-called "chopped". That is, to satisfy, everything that is not part of Base is cut off! Thus, the above code displays "Base!".
If we need the intended output, we need to make the parameter not a value:
void foo(Base& x) // polymorphic { x.do(); } Our code above will then display βDerived!β Because it no longer slices. (You can also use a pointer.)
So take a look at the catch clause:
catch (exception e) Here, any exceptions that you selected will be cut into the base class std::exception , losing any derived information! This is why it is much more common (and possibly "correct") for linking to a link:
catch (const exception& e) You will now find that e.what() returns an uncut error message as intended.
Old
Here's how it should look (don't use using namespace in the 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) {} Old
Because these exception classes are declared inside the standard namespace, but yours is not. string is inside the 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 that I changed the parameter name. Names containing double underscores are reserved and you should not use them.
He says the function is undefined because you forgot to define it. Try the following:
#include <string> #include <stdexcept> using namespace std; class rpn_expression_error : public logic_error { public: explicit rpn_expression_error(const string& arg) : logic_error( arg ) { } // definition }; Like others, using namespace is bad practice in the header file, so if it is a header,
#include <string> #include <stdexcept> class rpn_expression_error : public std::logic_error { public: explicit rpn_expression_error(const std::string& arg) : logic_error( arg ) { } // definition }; Also, if your RPN expressions are not hardcoded, the errors in them will be runtime_error s, not logic_error s.
If this is your code, then the problem (as I said, and Adrian also said) is that you declared a constructor for your rpn_expression_error class, but you did not define it. Try adding this to your code (under the class declaration):
rpn_expression_error::rpn_expression_error(const string& arg) : logic_error(arg) { }