C++中按基类引用捕获派生类异常为何仍出现切片问题?
问题根因
首先要纠正你的误解:你的代码并没有发生对象切片,问题出在what()函数的签名不匹配,没有正确实现基类虚函数的覆盖。
- C要求派生类要覆盖基类的虚函数,函数签名必须和基类完全一致。
std::exception中what()的标准签名是virtual const char* what() const noexcept(C11之前为virtual const char* what() const throw())。 - 你在
bad_hmean里定义的what()为const char *what(),缺少了const修饰符,这不是对基类虚函数的覆盖,只是一个和基类同名的非虚成员函数,只会隐藏基类的同名函数。
不同捕获方式的行为差异
- 当你用
std::exception& e捕获异常时,变量的静态类型是std::exception,编译器查找what()时会调用基类的虚函数实现,也就是你初始化std::logic_error时传入的字符串BAD HARMONIC MEAN VALUES。 - 当你用
bad_hmean&捕获异常时,变量的静态类型是bad_hmean,编译器会直接调用你定义的非虚what()函数,输出拼接好的预期内容。
修复方案
修改bad_hmean的what()函数签名,和基类保持一致即可,建议额外加override关键字,让编译器在签名不匹配时直接报错,提前规避这类问题:
const char *what() const noexcept override { return what_; }
另外你的实现还存在内存安全风险:抛出异常时会生成异常对象的拷贝,默认拷贝构造函数只会拷贝what_指针,会导致多个对象指向同一块堆内存,最终触发double free。建议改用std::string存储报错内容,避免手动管理内存。
内容的提问来源于stack exchange,提问作者Nikola Vugdelija
相关产品推荐
相关产品推荐

