Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 773
Janusz Avatar asked Jun 29 '09 18:06

Janusz


2 Answers

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.

like image 140
Martin York Avatar answered Sep 19 '22 10:09

Martin York


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)

like image 32
Dario Avatar answered Sep 23 '22 10:09

Dario