【问题标题】:Why is my exception sliced to base class if I catch it with reference to base class?如果我参考基类捕获它,为什么我的异常会被切分到基类?
【发布时间】:2021-11-23 16:29:53
【问题描述】:

所以我写了一个小的 C++ 类如下:

class bad_hmean : public std::logic_error {
    const char *nature_;
    char *what_;

public:
    bad_hmean(const char *fname);

    ~bad_hmean() { delete[] what_; }

    const char *what() { return what_; }
};

inline bad_hmean::bad_hmean(const char *fname):nature_("BAD HARMONIC MEAN VALUES"), std::logic_error("BAD HARMONIC MEAN VALUES")
{
    int len = strlen(fname) + strlen(nature_)+3;
    what_ = new char [len];
    strcpy(what_, fname);
    strcat(what_, ": ");
    strcat(what_, nature_);
}

我已经尝试在以下主目录中对其进行测试:

void fun1() { throw bad_hmean(__func__); }

int main()
{
    try
    {
        fun1();
    } catch(std::exception& e)
    {
        std::cout << e.what();
    }
}

当我运行它时,我遇到了一个我无法解决的问题。即使我按值抛出异常并通过引用捕获它,切片仍然发生,因为我的代码输出是:BAD HARMONIC MEAN VALUES。 但是,如果我将异常捕获为对 bad_hmean 的引用,则输出就是我想要的: fun1:不好的谐波平均值

有人知道为什么会这样吗?

【问题讨论】:

  • what() 是虚函数,因此应该正确调用它,因为它是绑定到具有虚表的对象而不是静态的。它在 std::exception 类中被声明为虚拟。
  • 如果异常类 bad_hmean 被复制(并且需要复制异常),那么您将遇到双重破坏问题(因为类中断 The Rule of Three)。轻松修复 - 用 std::string 替换手动管理的 c-string。首选修复 - 将异常类替换为 std::runtime_error 或您自己的从 std::runtime_error 派生的类

标签: c++ c++11 exception gcc object-slicing


【解决方案1】:

bad_hmean 没有正确覆盖 what()。它应该与基类what 的签名匹配为:

const char *what() const noexcept { return what_; }
//                 ^^^^^ ^^^^^^^^

顺便说一句:最好使用override specifier(C++11 起)来确保函数覆盖基类中的虚函数。例如

const char *what() const noexcept override { return what_; }

【讨论】:

  • 哦,你是对的。我以后会更聪明,让IDE为我自动完成虚拟功能。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 2012-01-22
  • 2011-02-06
  • 1970-01-01
相关资源
最近更新 更多