12

我来自 Java 世界,目前正在构建一个小型 c++ 程序。我有一个对象可以做一些工作,然后将工作结果作为列表返回。

现在一天后我改变了对象的行为,将结果保存在一个集合中,以避免容器中的重复。但是我不能简单地返回集合,因为我第一次使用了一个列表作为接口。是否有一个通用的容器接口可以用来指定我的对象的接口而忘记我在内部使用的容器类型?

目前我正在创建一个添加所有值的集合,然后从集合中创建一个列表:

return std::list<foo>(this->mySet.begin(), this->mySet.end())

似乎有点奇怪。

4

4 回答 4

13

容器的概念体现在迭代器中。
正如您所见,对特定类型的容器进行硬编码可能不是您想要的。所以让你的类返回迭代器。然后,您可以重新使用容器迭代器。

class MyClass
{
    private:
        typedef  std::list<int>            Container;
    public:
        typedef  Container::iterator       iterator;
        typedef  Container::const_iterator const_iterator; 


        iterator        begin()        {return myData.begin();}
        const_iterator  begin() const  {return myData.begin();}

        iterator        end()          {return myData.end();}
        const_iterator  end()   const  {return myData.end();}

    private:
        Container   myData;
};

现在,当您将 Container 类型从 std::list 更改为 std::set 时,没有人需要知道。
此外,通过使用其他容器使用的标准名称,您的类开始看起来像 STL 中的任何其他容器。

注意:返回 const_iterator 的方法应该是 const 方法。

于 2009-06-29T19:25:00.940 回答
12

包括其容器在内的整个 C++ 标准库 - 与 Java 不同 - 不是接口(继承、多态),而是基于模板(为了提高效率)。

您可以围绕您的集合创建一个多态包装器,但这不是 C++ 方式。

最简单的解决方案就是使用一些类型别名来简化程序:

#include <iostream>
#include <list>
#include <vector>

using namespace std;

class Test {

private:
    typedef vector<int> Collection;

    Collection c;

public:

    typedef Collection::const_iterator It;

    void insert(int Item) {
        c.push_back(Item);
    }

    It begin() const { return c.begin(); }
    It end()   const { return c.end(); }

};

int main() {

    Test foo;

    foo.insert(23);
    foo.insert(40);

    for (Test::It i = foo.begin(); i != foo.end(); ++i)
        cout << *i << endl;

    return 0;
}

您现在可以更改Collection-typedef 而无需更改任何其他内容。(注意:如果您Collection公开,用户将能够引用您明确使用的类型)

于 2009-06-29T19:06:19.743 回答
3

不存在接口。相反,您通常会使用模板,并简单地说“我不在乎它是什么类型,只要它充当容器即可”。

假设您的函数如下所示:

std::list<int> DoStuff()

它可以这样调用:

template <typename container_type>
void caller() {
  container_type result = DoStuff();
}

如果您决定改为返回 a,则只需更改第一个函数set。调用函数并不真正关心(当然,只要您不依赖列表的细节)。

如果您发布更多示例代码,我们可能会更好地建议应该如何在 C++ 中完成。

于 2009-06-29T19:17:17.240 回答
2

根据您的描述,我认为简短的答案是否定的。

一般来说,当我创建某种形式的这样的集合时,我通常会使用 typedef 来指定我正在使用的容器:

class Object {
   typedef std::list<int> Cont;
   typedef Cont::iterator iterator;
   typedef Cont::const_iterator const_iterator;

   // ....
};

所有客户端代码都是指“Object::Cont”等,所以只要客户端只使用容器的一般特性,容器发生变化就不需要改变。

如果您现在无法更改 API,那么我认为您的解决方案非常好,但是,根据您拥有的数据,如果您执行了很多往往是唯一的插入,那么继续使用可能会更有效列出并仅在末尾删除重复项:

void foo (std::list<int> & list) {

  // ... fill the list

  list.sort ();
  list.unique (); 
}
于 2009-06-29T19:16:57.710 回答