Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "inherit" an iterator from an STL class?

I'm trying to create a class of objects called tableaux, which are essentially vectors of vectors of unsigned ints (they're like matrices except the rows can be different lengths) with some algorithms I have written. The main problem is that I want to inherit iterators for these objects from the vector class and I don't know how.

I've read several related questions and answers, and it's pretty easy for me to just inherit std::vector<std::vector<unsigned int> > publicly, but the consensus is that this is bad for reasons of STL containers not having virtual destructors or whatever. So I've decided to try and "inherit" by composition. Here is a somewhat-minimal example of what I'm trying to achieve:

#include <vector>
#include <iostream>

class tableau {
  private:
    std::vector<std::vector<unsigned int> > rep;
  public:
    using std::vector<std::vector<unsigned int> >::iterator;
    void push_back(std::vector<unsigned int> const& new_row) {
      rep.push_back(new_row);
    }
};

int main() {
  tableau t1;
  std::vector<unsigned int> row1(10);
  std::vector<unsigned int> row2(8);

  t1.push_back(row1);
  t1.push_back(row2);

  tableau::iterator it = t1.begin();
  for ( ; it != t1.end(); ++it) {
    //display rows of tableau
  }
  return 0;
}

But then g++ gives me the error: type 'std::vector<std::vector<unsigned int> >' is not a base type for type 'tableau'. I'm just starting to learn C++ so please be gentle if I did something stupid. If you want more of the actual code I have written, let me know.

like image 744
Chris Brooks Avatar asked Jan 16 '14 19:01

Chris Brooks


1 Answers

Your first problem is that using doesn't allow you to steal types from arbitrary unrelated types (though you could use typedef for this). Also, you have no begin() or end() members.

Resolving these issues results in the following:

#include <vector>
#include <iostream>

class tableau {
  private:
    std::vector<std::vector<unsigned int> > rep;
  public:
    typedef std::vector<std::vector<unsigned int> >::iterator iterator;
    void push_back(std::vector<unsigned int> const& new_row) {
      rep.push_back(new_row);
    }
    iterator begin() { return rep.begin(); }
    iterator end()   { return rep.end();   }
};

int main() {
  tableau t1;
  std::vector<unsigned int> row1(10);
  std::vector<unsigned int> row2(8);

  t1.push_back(row1);
  t1.push_back(row2);

  tableau::iterator it = t1.begin();
  for ( ; it != t1.end(); ++it) {
    //display rows of tableau
  }
  return 0;
}

However, your approach means you're going to have to wrap every single function you want to call.

If I were you I'd stick with inheritance: though the advice you cite is correct, that doesn't mean inheritance is impossible. You're never going to want to use your tableau polymorphically through a pointer-to-base, so simply document that nobody should ever try to do this, and you'll be fine.

(When you make use of "composition" it's called "composing". You're asking how to "compose" the vector.)

like image 54
Lightness Races in Orbit Avatar answered Sep 19 '22 14:09

Lightness Races in Orbit