如何将asString()/ toString()添加到std :: vector?

时间:2011-08-29 14:15:32

标签: c++ inheritance stl

我的情况如下:有一些类MyList可能会在稍后获得特定的实现。现在,像std :: vector这样的行为很好。

但是,我真的需要一种简单的方法来调用某种asString()/ toString()方法,因为我需要它在测试断言,调试输出等等。我看到的唯一选择是:

  1. 公共继承权。我永远不会通过基指针删除这样的列表,因为永远不应该有任何基本指针。如果我这样做,反正将没有指针成员。但是,经验法则仍然指出:不要从stl容器继承。

  2. 某种“全局”(实际上在命名空间中)当然是将MyList的实例作为参数并为我执行asString()魔术的方法。在这种情况下,MyList可能是std :: vector的简单typedef。

  3. 我不太喜欢这些选项。还有什么我没想到的吗?或者如果不是 - 我应该选择哪种方式?

8 个答案:

答案 0 :(得分:8)

第二种方法有什么问题?这是迄今为止最简单,也很优雅.- 想象一下包装矢量的替代方案。这将导致你很多额外的工作和胶水代码容易出错!我肯定会采用功能方法!

编辑:顺便说一句,我几乎只使用免费功能(有时是静态成员)进行转换。想象一下,你有一些类型的东西,不知何故需要转换为字符串。让toString()函数作为自由函数而不是成员不会让你头疼,因为你基本上可以简单地重载函数,而不必触及任何现有的类(或者可能)您甚至没有源访问权限的类。)

然后你可以有一个像:

这样的功能
template<class T>
void printDebugInfo(const T & _obj)
{
   std::cout<<toString(_obj)<<std::endl;
}

你不会遇到你遇到的限制。

答案 1 :(得分:6)

实际上,类类型的自由函数是一种标准技术,被认为是类型接口的一部分。阅读Herb Sutter的this GotW,这是一位在C ++标准化方面有发言权的人。

通常,更喜欢免费功能而不是成员功能。这增加了封装和可重用性,并减少了类膨胀和coupling。请参阅Scott Meyers的this article以获取更深入的信息(如果您希望提高对C ++的有效和清晰使用,那么您应该阅读的C ++书籍备受推崇。)

另请注意,您永远不应从STL容器派生。它们不是作为基类设计的,您可以轻松调用未定义的行为。但请参阅Is there any real risk to deriving from the C++ STL containers?

答案 2 :(得分:3)

我认为有一个免费的

std::string toString( const MyList &l );

功能非常好。如果您害怕名称冲突,可以按照您的说法考虑命名空间。此函数高度分离,无法修改MyList个对象的私有成员(如成员或朋友函数的情况)。

只有 的理由才能证明它不是免费功能:你注意到你突然需要扩展MyList的公共接口,以便能够正确实现toString 。在那种情况下,我会把它变成朋友的功能。

答案 3 :(得分:2)

如果你做了类似的事情:

template<typename T>
std::ostream& operator<< (std::ostream &strm, const MyList<T> &list)
{
    if (list.empty())
        return strm;

    MyList<T>::const_iterator iter = list.begin(),
                              end = list.end();
    // Write the first value
    strm << *iter++;

    while (iter != end)
         strm << "," << *iter++;

    return strm;
}

那么只要元素实现了流媒体操作符,你就可以为列表中的任何内容添加一个字符串

答案 4 :(得分:1)

您是否考虑过组成,而不是继承?即,您的MyList的成员变量类型为std::vector

您可能会抱怨现在需要在std::vector中复制MyList的API。但是你说你可能会在以后更改实现,所以无论如何你都需要这样做。您也可以立即执行此操作,以避免以后更改所有客户端代码。

答案 5 :(得分:1)

在这种情况下,继承是完全错误的。

全球功能方法非常好。

C ++中的一种“方法”是重载operator <<并使用stringstream来输出你的矢量或其他东西。

答案 6 :(得分:1)

我会使用全局模板函数printOnStream。这样,您可以轻松添加对其他数据类型的支持,并且使用流比创建字符串更通用。

我不会使用继承,因为可能会有一些棘手的情况。基本的是你提到的 - 缺少虚拟析构函数。但是,所有期望std :: vector的东西都无法正常处理您的数据类型 - 例如,您可能遇到切片问题。

答案 7 :(得分:0)

为什么调试和断言方法不能为您执行此操作?