这是在 <stdexcept>
中定义的异常:
class length_error : public logic_error
{
public:
explicit length_error(const string& __arg);
};
这是我的异常(exception)情况:
#include <string>
#include <stdexcept>
using namespace std;
class rpn_expression_error : public logic_error
{
public:
explicit rpn_expression_error(const string& __arg);
};
为什么在 <stdexcept>
时会出现此错误?不是吗?
Undefined symbols:
rpn_expression_error::rpn_expression_error(/*string*/ const&), referenced from:
...
ld: symbol(s) not found
应@sbi 的要求,这是我目前代码的一个最小示例:
#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;
}
}
我将其保存为 rpn.cpp
然后跑了make rpn
产生错误。
代码现在已完全构建,但是,实际程序仍然给我原始错误。
注意/解决方案:虽然上面的代码运行得很好,但实际代码中的相同异常类仍然会产生链接器错误。为了简化,我只是提升了 rpn_expression_error
到它自己的全局范围类,这似乎解决了问题。
最佳答案
您捕获异常的方式存在问题。具体来说,请考虑以下代码:
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); // <--
}
在那条标记线上,d
得到所谓的“切片”。也就是说,为了满足作为 Base
的要求,所有不属于 Base
的部分都会被切掉!所以上面的代码会输出“Base!”。
如果我们想要预期的输出,我们需要使参数不是值:
void foo(Base& x) // polymorphic
{
x.do();
}
我们上面的代码将显示“Derived!”,因为它不再被切片。 (也可以使用指针。)
所以,看看你的 catch 子句:
catch (exception e)
在这里,您抛出的任何异常都将被切片到基础 std::exception
类中,从而丢失任何派生信息!这就是为什么按引用捕获更常见(并且可能“正确”)的原因:
catch (const exception& e)
您现在会发现 e.what()
按预期返回了非切片错误消息。
旧
这是整个事情的样子(不要在 header 中使用 using namespace
!):
// 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)
{}
年长
因为那些异常类是在标准命名空间内声明的,而你的不是。 string
位于命名空间 std
内,因此他们不需要对其进行限定,但您需要:
#include <string>
// ...
vvv
explicit rpn_expression_error(const std::string& arg);
请记住,我已经更改了您的参数名称。包含双下划线的名称是保留名称,您不应使用它们。
关于c++ - 从 stdexcept 类继承时为 "Undefined Symbols",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2459034/