以下是<stdexcept>
:
class length_error : public logic_error
{
public:
explicit length_error(const string& __arg);
};
这是我的例外:
#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
提升为自己的全局范围类,这似乎解决了这个问题。
答案 0 :(得分:3)
您捕获异常的方式存在问题。具体来说,请考虑以下代码:
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()
按预期返回非切片错误消息。
以下是整个事物的外观(不要在标题中使用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);
请记住我已更改参数名称。包含双下划线的名称是保留的,您不应该使用它们。
答案 1 :(得分:1)
看起来你已经声明了一个构造函数但没有提供一个定义。
答案 2 :(得分:1)
它表示函数未定义,因为您忘了定义它。试试这个:
#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
};
正如其他人所建议的那样,using namespace
在头文件中的做法很差,所以如果这是一个标题,
#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
};
此外,除非你的RPN表达式都是硬编码的,否则它们中的错误将是runtime_error
s,而不是logic_error
s。
答案 3 :(得分:0)
如果这是你的代码,那么问题是(正如我建议和Adrian所说)你已经为你的rpn_expression_error
类声明了一个构造函数,但是你还没有定义它。尝试将此添加到您的代码中(在您的类声明下面):
rpn_expression_error::rpn_expression_error(const string& arg)
: logic_error(arg)
{
}