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

时间:2014-05-05 15:25:10

标签: c++ templates inheritance forward-declaration stdstring

经常讨论无法转发声明std :: string和std :: wstring的问题。据我了解,原因是这些类型是模板类basic_string实例化的typedefing:

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?

2 个答案:

答案 0 :(得分:8)

  

使用继承代替typedef [...]

对c ++标准不会更好

没有

std :: basic_string不打算以任何形式继承。这个限制允许实现std :: basic_string,因为它没有虚函数表,所以创建和销毁要便宜得多(更快)。

如果你需要定义std :: [w]字符串,只需要#include

修改(回答评论)

C ++(和标准库)的指导原则之一是#34;不支付你不使用的东西&#34;。这意味着代码以这样的方式编写,您不应该为不需要的功能带来运行时成本。

如果每个实例都有一个虚拟表,那么创建一个std :: string实例将会更加昂贵(这将使得使用std :: string,在性能关键代码中是禁止的。)

相反,std :: string旨在作为C char*机制的快速,类型安全的RAII实现。同样,你不应该尝试从std :: vector,list,map,shared_ptr,unique_ptr等继承。

如果你真的需要一个字符串基类,考虑自己编写一个your_namespace::[w]string_base(一个简单的实现将是一个内部封装std::[w]string的实现。)

答案 1 :(得分:1)

“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的成员,如果它们不是真正的typedef,则不会返回stringwstring 。这导致了各种微妙的问题。