: class length_error : public logic_erro...">

"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.

+4
source share
4 answers

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.

+3
source

It looks like you declared a constructor, but did not give a definition for it.

+1
source

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.

+1
source

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) { } 
0
source

Source: https://habr.com/ru/post/1304320/


All Articles