2
class IFeature
{
public:
  virtual std::string string() = 0;
};

class Feature2D
{
public:
  virtual std::string string() { .... }
};

class Feature3D
{
public:
  virtual std::string string() { .... }
};

void print(std::vector<IFeature*> & v)
{
  for (size_t i=0; i<v.size(); i++)
    std::cout << v[i]->string() << std::endl;
}

void main()
{
  std::vector<Feature2D*> v2d;
  // push...
  print(v2d); // compile error 

  std::vector<Feature3D*> v3d;
  // push...
  print(v3d); // compile error 
}

Any suggestions on how I can obtain this print function? (maybe using another data structure different by std::vector)

Thanks

3
  • 1
    You can (and should) pass your vectors to print by const reference. Also, the inheritance statement is missing on your FeatureXD class declarations. Commented Feb 17, 2011 at 12:02
  • @Stefan - please don't suggest edits to the code posted in questions. It may well be that any errors are the cause of the problem the OP is seeing. Commented Feb 17, 2011 at 12:47
  • Yes, of course, what was I thinking :) Commented Feb 17, 2011 at 14:11

5 Answers 5

2

Use a template.

template<typename T> void print(std::vector<T *> const & v) {
  for (size_t i=0; i<v.size(); i++)
    std::cout << v[i]->string() << std::endl;
}

Or, use a virtual print member function:

class IFeature
{
public:
  virtual std::string string() = 0;
  virtual void print(std::ostream & Dest) const = 0;
};

void print(std::vector<IFeature *> const & v) {
  for (size_t i=0; i<v.size(); i++) {
    v[i]->print(cout);
    cout << endl;
  }
}

Optionally combine with an operator<<

inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v) {
  v.print(Dest);
  return Dest;

void print(std::vector<IFeature *> const & v) {
  for (size_t i=0; i<v.size(); i++)
    std::cout << *(v[i]) << std::endl;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much! What that "const" is for?
It indicates that the print will not modify v.
2

Just make the vectors IFeature* -vectors. You can store pointers for inherited classes in them just fine.

std::vector<IFeature*> v2d;
v2d.push_back(new Feature2D());
print(v2d);

No need to use templates. Pointers to the superclass are the way to go when you need to access common virtual functions. This way you can also mix different subclasses inside the same vector:

std::vector<IFeature*> vMixed;
vMixed.push_back(new Feature2D());
vMixed.push_back(new Feature3D());
print(vMixed);

Of course, if you also need pointers for the inherited classes, things get a bit more tricky. One option is to store them elsewhere separately. You can also downcast, but that is not usually recommendable.

1 Comment

This won't work if you need to access the inherited class through the vector, though. (You'd need ugly downcasts.)
1

For the sake of completeness, I'll add that you can reinterpret_cast the vectors, since all vector share the same binary code.

print(reinterpret_cast<std::vector<IFeature*>&>(v2d));

C++ doesn't have covariance for template parameters, but you can simulate it partly if you know what it does under the hood. I found reinterpret_cast to be also useful to convert vector<T*>& to vector<const T*>& for contravariance.

Granted, this is very ugly.

Comments

1

You can make print itself into a template:

template<typename T>
void print(T const &v)
{
  for (size_t i=0; i<v.size(); i++)
    std::cout << v[i]->string() << std::endl;
}

Better yet, use iterators, then it'll work on most other standard containers as well:

template<typename T>
void print(T const &v)
{
  for (T::const_iterator i = v.begin(); i != v.end(); ++i)
    std::cout << (*i)->string() << std::endl;
}

Even better (thanks Pedro), pass the iterators themselves:

template<typename Iter>
void print(Iter begin, Iter end) {
  for (Iter i = begin; i != end; ++i)
    std::cout << (*i)->string() << std::endl;
}

1 Comment

I'd go one step further and suggest you operate on iterators rather than on a const reference to T. So: template <typename InputIterator> void print(InputIterator begin, InputIterator end) { ... }
0

What you are looking for here is interface covariance, which (as far as I know) is not possible on C++ classes. You need to make print also a Templated function (replace IFeature* with T*).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.