C ++中集合/容器的接口/超類 (Interface/Superclass for Collections/Containers in c++)


問題描述

C ++中集合/容器的接口/超類 (Interface/Superclass for Collections/Containers in c++)

I'm coming from the Java world and are building a small c++ program at the moment. I have an object that does some work and then returns the result of the work as a list. 

Now a day later i changed the behavior of the object to save the results in a set to avoid duplicates in the container. But I can't simply return the set because I used a list for the interface in the first time.  Is there a common container interface that I can use to specify the interface of my object and forget about the container type I use internally?

At the moment I'm creating a set adding all the values and then creating a list from the set:

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

Seems a little strange.


參考解法

方法 1:

The concept of a container is enbodied by iterators. As you have seen hard coding a specific type of container is probably not what you want. So make your class return iterators. You can then re-use the conatiners iterators.

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;
};

Now when you change the Container type from std::list to std::set nobody needs to know. Also by using the standard names that other containers use your class starts to look like any other container from the STL.

Note: A method that returns a const_iterator should be a const method.

方法 2:

The whole C++- standard library including its containers is - unlike Java - not interface (inheritance, polymorphism)- but template-based (for the sake of efficiency).

You could create a polymorphic wrapper around your collection but this isn't the C++-way.

The simplest solution is just to simplify the programm with some type aliases:

#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;
}

You can now change the Collection-typedef without having to change anything else. (Note: If you make Collection public, the user will be able to refer the the type you used explicitly)

方法 3:

No interface exists. Instead, you would typically use templates, and simply say "I don't care what type it is, as long as it behaves as a container".

Assuming your function looks like this:

std::list<int> DoStuff()

it can be called like this:

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

Only the first function has to be changed if you decide to return a set instead. The calling function doesn't really care (as long as you don't rely on the specifics of a list, of course).

If you post a bit more sample code, we might be better able to suggest how it should be done in C++.

方法 4:

From your description I think the short answer is no.

In general when I'm creating some form of collection like this I would normally use a typedef to specify the container that I'm using:

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

   // ....
};

All client code refers to "Object::Cont" etc. and so as long as clients only use the general features of containers, they will not need to change if the container changes.

If you cannot change your API now, then I think your solution is pretty good, however, depending on the data that you have, if you do a lot of inserts that tend to be unique, then it may be more efficient to continue using the list and only remove duplicates at the end:

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

  // ... fill the list

  list.sort ();
  list.unique (); 
}

(by JanuszMartin YorkDariojalfRichard Corden)

參考文件

  1. Interface/Superclass for Collections/Containers in c++ (CC BY-SA 3.0/4.0)

#collections #containers #interface #C++ #language-design






相關問題

C ++中集合/容器的接口/超類 (Interface/Superclass for Collections/Containers in c++)

如何將對象列表轉換為兩級字典? (How to convert a list of objects to two level dictionary?)

如何在java中限制哈希集的默認排序 (how to restrict default ordering of Hash Set in java)

將兩個單獨的 Set 轉換為二維數組 (Convert two separate Sets to a 2D array)

事件調度線程從列表異常 SWING 中移除 (Event dispatching thread remove from List exception SWING)

將集合項複製到 .NET 中的另一個集合 (Copy collection items to another collection in .NET)

java - 如何在java中使用某些特定索引將值存儲到arraylist中 (how to store value into arraylist with some specific index in java)

將對象添加到具有主幹的第一個位置的集合中? (Adding object to a Collection in the first position with backbone?)

在VB中過濾一個wpf collectionviewsource? (Filter a wpf collectionviewsource in VB?)

將流式數據讀入排序列表 (Reading streamed data into a sorted list)

有沒有一種自動處理數組和強類型集合之間轉換的好方法? (Is there a good way to handle conversions between arrays and strongly typed collections automatically?)

將數據行轉換為 1 個對象 (Convert data rows to 1 object)







留言討論