当前位置:  开发笔记 > 编程语言 > 正文

有关使用用户定义的方法扩展C++ STL容器的更好方法的建议

如何解决《有关使用用户定义的方法扩展C++STL容器的更好方法的建议》经验,为你挑选了4个好方法。

我从C++ STL容器继承并添加我自己的方法.理由是,对于客户来说,它看起来像是一个常规列表,但是它们可以很容易地被称为特定于应用程序的方法.

这很好,但我读过很多关于不从STL继承的帖子.有人可以提供一个具体的建议,告诉我如何以更好的方式编写下面的代码吗?

class Item
{
  int a;
  int b;
  int c;

  int SpecialB()
  {
    return a * b + c;
  }
};

class ItemList : public std::vector
{
  int MaxA()
  {
    if( this->empty() )
      throw;

    int maxA = (*this)[0].a;

    for( int idx = 1; idx < this->size(); idx++ )
    {
      if( (*this)[idx].a > maxA )
      {
        maxA = (*this)[idx].a;
      }
    }
    return maxA;
  }

  int SpecialB()
  {
    if( this->empty() )
      throw;

    int specialB = (*this)[0].SpecialB();

    for( int idx = 1; idx < this->size(); idx++ )
    {
      if( (*this)[idx].SpecialB() < specialB )
      {
        specialB -= (*this)[idx].c;
      }
    }
    return specialB;
  }

  int AvgC()
  {
    if( this->empty() )
      throw;

    int cSum = 0;
    for( int idx = 0; idx < this->size(); idx++ )
    {
      cSum += (*this)[idx].c;
    }

    return cSum / this->size(); // average
  }
};

编辑:谢谢你的一些深思熟虑的答案.我将创建辅助函数,从现在开始将永远不会从STL容器继承.



1> Todd Gamblin..:

这是个主意.

你不应该从STL类派生出很多原因,其中最重要的原因是它们不是为它设计的.Vector没有虚拟析构函数,所以如果扩展它,可能无法正确调用超类的析构函数,并且会导致内存泄漏.

有关此问题的更多信息,请参阅此答案,了解为何从中获取std::string.许多相同点适用:

构造函数不适用于从std :: string继承的类

没有虚拟析构函数

没有受保护的功能(所以你继承的任何东西都没有)

多态性不起作用,你将获得对象切片. std::vector是可分配的,但是如果添加自己的字段,如果从向量指针或向量引用分配,它们将不会被赋值复制.这是因为vector我们operator=不知道你的领域.

出于所有这些原因,您最好使用实用功能而不是扩展到STL.



2> bayda..:

为什么你需要这种扩展矢量?

与你的仿函数一起使用标准.
例如

std::min_element, std::max_element

int max_a = std::max_element
        ( 
            v.begin(), 
            v.end(), 
            boost::bind( 
                std::less< int >(),
                bind( &Item::a, _1 ), 
                bind( &Item::a, _2 ) 
            )
        )->a;

std::accumulate - 计算平均值

const double avg_c = std::accumulate( v.begin(), v.end(), double( 0 ), boost::bind( Item::c, _1 ) ) / v.size(); // ofcourse check size before divide  

您的ItemList :: SpecialB()可以重写为:

int accumulate_func( int start_from, int result, const Item& item )
{
   if ( item.SpecialB() < start_from )
   {
       result -= item.SpecialB();
   }
   return result;
}

if ( v.empty() )
{
    throw sometghing( "empty vector" );
}
const int result = std::accumulate( v.begin(), v.end(), v.front(), boost::bind( &accumulate_func, v.front(), _1, _2 ) );

顺便说一句:如果您不需要访问成员,则不需要继承.



3> Evan Teran..:

由于您只能通过使用其公共接口"扩展"向量,因此编写对向量进行操作而不是向量的一部分的函数更有用.

哎呀,如果你计划得好,让它与迭代器而不是索引一起工作,它不仅可以工作std::vector(参见一些非常好的例子).

例如,您可以像这样使用MaxA的仿函数:

struct CmpA {
    bool operator()(const Item &item1, const Item &item2) { return item1.a < item2.a; }
}

const int result = std::max_element(v.begin(), v.end(), CmpA()).a;

你的specialB可以和functor一样简单 std::accumulate

编辑:或者对于c ++ 11及更高版本,它可以很简单:

const int result = std::max_element(v.begin(), v.end(), [](const Item &item1, const Item &item2) {
    return item1.a < item2.a;
}).a;

编辑:你问过为什么这样做更好:

如果您使用算法,模板和迭代器,即使您决定将项目放在一个std::list或任何其他内容中,它也会起作用.它更简单,更有助于代码重用.

此外,这些功能还可以为您提供更多功能,因此您可以使用小型3线适配器仿函数.

编辑:除此之外,tgamblin列出了一些非常令人信服的理由不继承std::vector(以及大多数其他标准容器,包括std::string).



4> Bruce Ikin..:

我更喜欢使用stl容器作为实现细节,而不是作为我的解决方案界面的一部分.这样我就可以在没有任何调用代码受到影响的情况下更改容器(deque或list的向量).您可能必须通过函数编写一些调用,但封装值得额外输入.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有