为什么IO库和诊断库要使用继承?

问题描述 投票:0回答:1

很多C++ 标准库 使用模板而不是继承来实现多态性。 这是一个众所周知的话题关于原因²。有数百个关于这个主题的视频和博客文章。

至于标准库中确实使用继承的部分,我只能想到

  • 诊断库,其中标准库生成的所有异常都继承自
    std::exception
  • 以及输入/输出库,它具有通过继承层次结构捆绑在一起的十几个类,该继承层次结构还具有钻石

我的问题是:标准库的这两个部分必须满足哪些特殊要求/约束/目标/某些东西,要求(或要求!³)它们使用继承?


是的,模板实现了静态多态性和继承动态多态性,但这正是我问这个问题的原因。毕竟,标准库的算法正是通过模板工作的,因为它们的整个

定义都可以在headers中使用。如果由于某种原因需要独立编译算法,然后“链接”到客户端程序,那么(我的理解是)算法将必须使用某种类型的类型擦除,因此需要某种类型的运行时多态性。 (²) 是的,问题涉及STL。但我想即使接受这种模糊性,我认为自由的模板化部分和虚拟部分之间的不平衡仍然适用。

(³) 我想知道这两个库是否会基于

C++20 的模块

进行不同的设计。

(⁴)澄清:我不是在寻找类似的答案(参考诊断库)“哦,这很简单!这是因为你想要

std::logic_error

std::runtime_error

和其他例外来实现
what
 ,因此您可以在异常上调用 
.what
,而无需实际知道其具体类型!”
,因为单遍算法也“希望”其迭代器输入来实现
operator++
operator*
,但它们并不需要所有迭代器共享基类!
	

简单地阅读评论并尝试解决它们,促使我更深入地思考,我想我已经得到了一半的答案,一半是关于诊断库的。
c++ exception inheritance iostream design-decisions
1个回答
0
投票
事后看来,这似乎很明显。

给定如下所示的 TU,这可以

throw

例外。

// foo.hpp
void foo(bool b);

// foo.cpp #include "foo.hpp" void foo(bool b) { if (b) throw std::logic_error{"oops"}; else throw std::runtime_error{"oops"}; };
它可以与另一个捕捉这样的异常的 TU 链接
void bar(bool b) {
  try {
    foo(b);
  } catch(std::exception const& e) {
    // stuff I know
  } catch(...) {
    // stuff I don't know
  }
}

在这样的场景中,一个 TU 中生成的异常要被另一个 TU 捕获的唯一方法是前一个 TU 生成的异常必须是后一个 TU 捕获的异常类的子类。

所以我猜想,就诊断库而言,它从根本上使用基于继承的异常层次结构,因为它希望允许异常处理跨越多个翻译单元,这可能就是人们希望拥有异常机制的全部意义所在完全没有。


© www.soinside.com 2019 - 2024. All rights reserved.