Pergunta

This is a "best practice" question: I can think of several ways to do it, but I would like to know which one the community thinks is the best.

I have a method as follows:

void Foo(std::vector<BaseClass>& Objects) {...}

I now want to call this method on an Objects which is an std::vector<DerivedClass>.

I can think, e.g., of using a template, or converting Sort to take std::vector<BaseClass*> and then passing (Objects.begin(), Objects.end()).

Thanks in advance.

Foi útil?

Solução 2

Best practice would be to accept a pair of iterators delineating the range of elements upon which Foo should operate, possibly providing convenience functions to convert ranges to iterators:

template <typename Iter>
void Foo(Iter first, Iter last) {...}
void Foo(std::vector<BaseClass>& Objects) {
  Foo(begin(Objects), end(Objects));
}
void Foo(std::vector<DerivedClass>& Objects) {
  Foo(begin(Objects), end(Objects));
}

// Or even a generic range adaptor,
template <typename Range>
void Foo(Range&& r) {
  using std::begin; using std::end;
  Foo(begin(r), end(r));
}

Outras dicas

If you need dynamic polymorphism you may consider std::shared_ptr, std::unique_ptr or a class containing a pointer to a (internal) polymorph class. In other words 'std::vector< BaseClass* >' is plain ugly.

If you use static polymorphism (templates) the Sort will become a template, too.

You need a template.

There is absolutely no relationship between a std::vector<Base> and a std::vector<Derived>, nor between a std::vector<Base*> and a std::vector<Derived*>, nor any other wrapper. The language will not allow you to substitute these things without an unsafe typecast, which is just undefined behavior.

If you have a function that takes a std::vector<Base%> (substitute % by whatever), then that's what you need to pass. The only way to do that is to create a new vector of the correct type and fill it.

Or you make it so that the function is more flexible, and that's by making it a template.

If you intend to operate on the container's elements (e.g. sort them), I would suggest that you follow the convention that people would expect: that is, the pattern used in the standard library.

template<typename RandomAccessIterator>
void foo(RandomAccessIterator start, RandomAccessIterator end) { ... }

This way you make it easy to use for either of your classes (Base or Derived), and anyone else looking at your code should easily be able to tell what it is doing.

If you are attempting to sort, you can also provide a Predicate version of the template that allows you to provide a sorting method that is different from your default (e.g. if you want to sort largest to smallest).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top