扩展C++;继承的标准库? 通常认为C++标准库一般不打算使用继承来扩展。当然,我(和其他人)批评了那些建议从类派生的人,比如std::vector。然而,这个问题:让我意识到标准库中至少有一部分打算进行如此扩展-std::exception
因此,我的问题分为两部分:扩展C++;继承的标准库? 通常认为C++标准库一般不打算使用继承来扩展。当然,我(和其他人)批评了那些建议从类派生的人,比如std::vector。然而,这个问题:让我意识到标准库中至少有一部分打算进行如此扩展-std::exception,c++,stl,C++,Stl,因此,我的问题分为两部分: 是否有任何其他标准库类打算从中派生 如果从标准库类(如std::exception)派生,是否受ISO标准中描述的接口约束?例如,使用异常类的程序what()成员函数没有返回NTB(比如返回空指针)是否符合标准 a) 流库被设置为继承:)回答问题2): 我相信是的,他们将受到ISO标准接口描述的约束。例如,该标准允许全局重新定义运算符new和运算符delete。但是,该标准保证运算符delete在空指针上是一个no操作 不尊重这一点肯定是未定义的行为(至少对Scott
std::exception
)派生,是否受ISO标准中描述的接口约束?例如,使用异常类的程序what()
成员函数没有返回NTB(比如返回空指针)是否符合标准运算符new
和运算符delete
。但是,该标准保证运算符delete
在空指针上是一个no操作
不尊重这一点肯定是未定义的行为(至少对Scott Myers而言)。我想我们可以说,类比标准库的其他领域也是如此。对于第二个问题,我相信答案是肯定的。标准规定std::exception的what成员必须返回非NULL值。我是否有std::exception的堆栈、引用或指针值并不重要。what()的返回受标准约束
当然可以返回NULL。但是,我认为这样的类是非标准符合的。 < <代码>函数中的一些东西,如<代码>更大的< /代码>,<>代码> < >和<>代码> Mimu-Funtht >源于<代码> unyalx运算符< /COD>和<代码> Bialyx运算符< /C>。但是,IIRC,这只会给你一些类型定义。好问题。我真的希望标准能更明确地说明预期用途。也许应该有一个C++语言文档,它与语言标准并驾齐驱。在任何情况下,以下是我使用的方法: (a) 我不知道有这样的名单。相反,我使用以下列表来确定标准库类型是否可能被设计为继承自:
- 如果它没有任何
方法,那么您不应该将其用作基础。这排除了virtual
等std::vector
- 如果它确实有
方法,那么它可以作为基类使用virtual
- 如果有大量的
语句浮动,那么请避开,因为可能存在封装问题friend
- 如果它是一个模板,那么在继承它之前请仔细查看,因为您可能可以使用专门化来定制它
- 基于策略的机制(例如,
)的存在是一个很好的线索,说明您不应该将其用作基础std::char_traits
(b) 我会在这里申请。如果有人对您的异常调用
what()
,那么它的可观察行为应该与std::exception
的行为相匹配。我不认为这是一个标准一致性问题,而是一个正确性问题。该标准不要求子类可以替代基类。它实际上只是一个“最佳实践”。 < P> C++标准库不是单一的单元。它是组合和采用几个不同库的结果(C标准库的很大一部分、iostreams库和STL是三个主要的构建块,并且每一个都是独立指定的)
正如您所知,库的STL部分通常不是从中派生的。它使用泛型编程,通常避免面向对象编程
IOStreams库是更传统的面向对象编程,在内部大量使用继承和动态多态性,用户希望使用相同的机制来扩展它。自定义流通常通过从stream类本身或其内部使用的streambuf
类派生来编写。这两种方法都有可以在派生类中重写的虚拟方法
std::exception
是另一个例子
正如D.Shawley所说的,我将把这个问题应用到你的第二个问题上。用基类替换派生类应该是合法的。如果我调用exception::what()
,它必须遵循exception
类指定的约定,无论exception
对象来自何处,或者它是否实际上是一个已被升级的派生类。在这种情况下,该合同是标准公司关于返还非关税壁垒的承诺。如果你让一个派生类的行为不同,那么你会违反标准,因为一个类型的对象<代码> STD::异常< /代码>不再返回NTBS.< /P> < P> W.R.T问题2),根据C++标准,派生异常类必须指定一个“不抛出”即“丢())规范以及返回非空。这意味着在许多情况下,派生异常类不应使用std::string,因为std::string本身可能会根据实现而抛出。节约规则是“任何类别都可以用作基类;在没有虚拟方法(包括虚拟析构函数)的情况下安全使用它的责任完全由派生作者承担。“在std::exception的子类中添加非POD成员与在std::vector的派生类中添加非POD成员是相同的用户错误
class CfgValue : public std::string {
public:
...
CfgValue( const int i ) : std::string() { SetInteger(i); }
...
void SetInteger( int i );
...
int GetInteger() const;
...
operator std::wstring() { return utf8_to_ucs16(*this); }
operator std::wstring() const { return utf8_to_ucs16(*this); }
...
};