std::string和std::wstring的正向声明

forward declaration of std::string and std::wstring

本文关键字:std 声明 wstring string      更新时间:2023-10-16

经常讨论无法转发声明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]字符串,只需#includeit.

编辑(回答评论(

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::stringstd::wstring的重载而存在,但不是作为模板:

void bar(const std::string& s) {}
void bar(const std::wstring& s) {}

然后,如果你有一个真正的typedef,那就行了。如果使用继承,它将无法编译,或者将静默地创建要传递给bar的字符串副本,这是一个隐藏的性能陷阱。

或者采用substr成员函数。它返回与被调用时相同的类型,但这意味着如果它是basic_string的成员,则不会返回stringwstring(如果它们不是真正的typedef(。这导致了各种微妙的问题。

相关文章: