c++ - 从 stdexcept 类继承时为 "Undefined Symbols"

标签 c++ debugging inheritance exception

这是在 <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/

相关文章:

c++ - 将内联函数作为参数传递

c++ - 为什么使用存储在虚方法表中的地址调用虚函数会返回垃圾?

C++ 生成警告 : dereferencing type-punned pointer will break strict-aliasing rules

c++ - QTimer::singleShot() 在给定对象的父类中查找指定的槽,而不是对象本身

javascript - 原型(prototype)继承导致共享引用

c++ - CMake "OBJECT"库 : clang not linking properly

jQuery 无法使用 ID 访问 DOM 元素,但可以使用 .class

c - 如何仅通过内存地址定位bug?

c - 从符号服务器加载 msctf.dll 的 pdb 不起作用

ios - 类层次结构不适合继承模型