经常讨论无法转发声明std::string和std::wstring的问题。据我所知,原因是这些类型是模板类basic_string:实例化的类型定义
namespace std {
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
}
并且该语言不允许typedef的前向声明。
使用继承而不是typedef:的c++标准不是更好吗
namespace std {
class string : public basic_string<char> {};
class wstring : public basic_string<wchar_t> {};
}
这样我们就可以转发声明std::string和std::wstring了吗?
对于c++标准来说,使用继承而不是typedef〔…〕不会更好
没有。
std::basic_string不意味着以任何形式继承。这个限制允许实现std::basic_string,因为它没有虚拟函数表,所以创建和销毁成本更低(更快(。
如果您需要定义std::[w]字符串,只需#include
it.
编辑(回答评论(
C++(以及标准库(的指导原则之一是"不要为你不使用的东西付费"。这意味着代码是以这样一种方式编写的,即您不应该为不需要的功能产生运行时成本。
如果每个实例都有一个虚拟表,那么创建一个std::string实例的成本会高得多(这将使在性能关键代码中禁止使用std::字符串(。
相反,std::string旨在作为一种快速、类型安全的C char*
机制的RAII实现。类似地,您不应该尝试从std继承:vector、list、map、shared_ptr、unique_ptr等等
如果您真的需要一个字符串基类,可以考虑自己编写一个your_namespace::[w]string_base
(一个微不足道的实现是在内部封装std::[w]string
(。
"typedef派生类"并不等同于真正的typedef。
想象一下,我有一个功能应该同时适用于两个版本:
template <typename Ch>
void foo(const std::basic_string<Ch>& s) {
// do some stuff here
}
我需要做的事情包括调用第三方函数bar
,它作为std::string
和std::wstring
的重载而存在,但不是作为模板:
void bar(const std::string& s) {}
void bar(const std::wstring& s) {}
然后,如果你有一个真正的typedef,那就行了。如果使用继承,它将无法编译,或者将静默地创建要传递给bar
的字符串副本,这是一个隐藏的性能陷阱。
或者采用substr
成员函数。它返回与被调用时相同的类型,但这意味着如果它是basic_string
的成员,则不会返回string
或wstring
(如果它们不是真正的typedef(。这导致了各种微妙的问题。