7

我一直希望 STL 的字符串具有更多功能。由于对 STL 类型进行子类化是不行的,所以我看到的大多数推荐的扩展这些类的方法就是编写将类型作为第一个参数的函数(不是成员函数)。

我从来没有对这个解决方案感到兴奋。一方面,所有这些方法在代码中的位置并不一定很明显,另一方面,我只是不喜欢语法。我想用 . 当我调用方法时!

不久前,我想出了以下内容:

class StringBox
{
public:
   StringBox( std::string& storage ) :
       _storage( storage )
   {
   }

   // Methods I wish std::string had...
   void Format(); 
   void Split();
   double ToDouble(); 
   void Join(); // etc...

private:
  StringBox();

  std::string& _storage;
};

请注意,StringBox 需要引用 std::string 进行构造...这对其使用设置了一些有趣的限制(我希望,这意味着它不会导致字符串类扩散问题)...在我自己的代码中,我几乎总是只是在一个方法的堆栈上声明它,只是为了修改一个 std::string。

一个使用示例可能如下所示:

string OperateOnString( float num, string a, string b )
{
    string nameS;
    StringBox name( nameS );

    name.Format( "%f-%s-%s", num, a.c_str(), b.c_str() );

    return nameS;
}

我的问题是:StackOverflow 社区的 C++ 大师如何看待这种 STL 扩展方法?

4

7 回答 7

19

我从来没有对这个解决方案感到兴奋。一方面,所有这些方法在代码中的位置并不一定很明显,另一方面,我只是不喜欢语法。我想用 . 当我调用方法时!

我想$!---&在调用方法时使用!处理它。如果您要编写 C++ 代码,请遵守 C++ 约定。一个非常重要的 C++ 约定是尽可能首选非成员函数。

C++ 大师推荐这个是有原因的:

它提高了封装性、可扩展性和重用性。(std::sort可以与所有迭代器对一起使用,因为它不是任何单个迭代器或容器类的成员。而且无论你如何扩展std::string,你都不能破坏它,只要你坚持非成员函数。即使你无权访问或不允许修改类的源代码,您仍然可以通过定义非成员函数来扩展它)

就个人而言,我在您的代码中看不到重点。这不是更简单、更易读、更短吗?

string OperateOnString( float num, string a, string b )
{
    string nameS;
    Format(nameS, "%f-%s-%s", num, a.c_str(), b.c_str() );
    return nameS;
}

// or even better, if `Format` is made to return the string it creates, instead of taking it as a parameter
string OperateOnString( float num, string a, string b )
{
    return Format("%f-%s-%s", num, a.c_str(), b.c_str() );
}

在罗马,做罗马人,俗话说。尤其是当罗马人有充分的理由这样做时。尤其是当你自己的做法实际上并没有一个优势时。它更容易出错,让阅读您的代码的人感到困惑,非惯用的,而且它只是更多的代码行来做同样的事情。

至于您的问题是很难找到扩展的非成员函数,string如果这是一个问题,请将它们放在命名空间中。这就是他们的目的。创建一个namespace StringUtil或其他东西,并将它们放在那里。

于 2010-01-10T17:38:46.143 回答
16

由于我们大多数“大师”似乎都喜欢使用可能包含在命名空间中的免费函数,我认为可以肯定地说您的解决方案不会受欢迎。恐怕我看不到它有一个单一的优势,并且该类包含引用这一事实是对它成为悬空引用的邀请。

于 2010-01-10T17:35:52.200 回答
2

我会添加一些尚未发布的内容。Boost String Algorithms 库采用了免费的模板函数方法,它们提供的字符串算法对于任何看起来像字符串的东西都非常可重用:std::string、char*、std::vector、迭代器对……你的名字!他们把它们都整齐地放在 boost::algorithm 命名空间中(我经常用它using namespace algo = boost::algorithm来使字符串操作代码更简洁)。

因此,请考虑为您的字符串扩展使用免费的模板函数,并查看 Boost String Algorithms 以了解如何使它们“通用”。

要获得安全的 printf 样式格式,请查看Boost.Format。它可以输出到字符串和流。

我也希望一切都成为成员函数,但我现在开始看到曙光了。UML 和 doxygen 总是迫使我将函数放在类中,因为我被 C++ API == 类层次结构的想法洗脑了。

于 2010-01-10T19:13:03.057 回答
1

松散函数的问题在于它们是松散函数。

我敢打赌,你们中的大多数人已经创建了一个 STL 已经提供的功能,因为您根本不知道 STL 功能的存在,或者它可以完成您想要完成的事情。

这是一个相当惩罚性的设计,尤其是对于新用户。(STL 也增加了新内容,进一步增加了问题。)

谷歌:C++ 到字符串

有多少结果提到:std::to_string

我很可能会找到一些古老的 C 方法或一些自制版本,就像我会找到任何给定函数的 STL 版本一样。

我更喜欢成员方法,因为您不必费力寻找它们,也不必担心找到旧的弃用版本等。(即,string.SomeMethod 几乎可以保证是您应该使用的方法,它为您提供了一些具体的 Google 信息。)


C# 风格的扩展方法将是一个很好的解决方案。

  1. 它们是松散的功能。
  2. 它们通过智能感知显示为成员函数。

这应该让每个人都能做他们想做的事。

似乎它可以在 IDE 本身中完成,而不需要任何语言更改。

基本上,如果解释器对不存在的成员进行了某些调用,它可以检查头文件是否匹配松散的函数,并在将其传递给编译器之前对其进行动态修复。

当它加载智能感知数据时,可以做类似的事情。

我不知道这如何适用于现有函数,不应掉以轻心,但对于使用新语法的新函数,这应该不是问题。

    namespace StringExt
    {
        std::string MyFunc(this std::string source);
    }

它可以单独使用,也可以作为 std::string 的成员使用,IDE 可以处理所有繁重的工作。

当然,这仍然会留下方法分布在各种标头中的问题,这可以通过各种方式解决。

  1. 某种扩展头:string_ext,它可能包含常用方法。
  2. 唔....

在不引起问题的情况下,这是一个更难解决的问题...

于 2012-11-17T02:34:55.593 回答
1

如果字符串的范围与StringBox你可以得到段错误不同:

StringBox foo() {
  string s("abc");
  return StringBox(s);
}

至少通过声明赋值运算符和复制 ctor 来防止对象复制:

class StringBox {
  //...
  private:
    void operator=(const StringBox&);
    StringBox(const StringBox&);
};

编辑:关于 API,为了防止意外,我会制作StringBox自己的字符串副本。我可以想到两种方法来做到这一点:

  1. 将字符串复制到成员(不是引用),稍后获取结果 - 也作为副本
  2. 通过引用计数智能指针访问您的字符串,例如std::tr1::shared_ptror boost:shared_ptr,以防止额外的复制
于 2010-01-10T17:35:50.270 回答
0

如果您想扩展可用于对字符串进行操作的方法,我将通过创建一个具有将标准字符串作为参数的静态方法的类来扩展它。这样,人们可以自由使用您的实用程序,但无需更改其函数的签名即可学习新课程。

这稍微打破了面向对象的模型,但使代码更加健壮——即,如果您更改了字符串类,那么它对其他代码的影响就没有那么大了。

遵循推荐的指南,它们的存在是有原因的:)

于 2010-01-10T17:34:32.523 回答
0

最好的方法是使用模板化的自由函数。下一个最好的是私有继承struct extended_str : private string,顺便说一句,在 C++0x 中它会变得更容易,就像using构造函数一样。仅仅添加一些算法,私有继承太麻烦也太冒险了。你正在做的事情对任何事情都太冒险了。

您刚刚介绍了一个重要的数据结构来完成代码标点符号的更改。您必须为每个 Box 手动创建和销毁一个 Box string,并且您仍然需要将您的方法与本机方法区分开来。你很快就会厌倦这种约定。

于 2010-01-10T18:08:50.077 回答