I commonly face the situation where I introduce an abstract base class (call it Foo
) to store instances of different child classes (call them Bar
and Baz
) in a container (e.g., std::vector<std::unique_ptr<Foo>>
). For the sake of illustration, let me put these sample classes here:
class Foo {
public:
virtual int getId() const = 0;
};
class Bar : public Foo {
public:
Bar(int id) : id_(id) {}
int getId() const override { return id_; }
private:
int id_;
};
class Baz : public Foo {
public:
Baz(int id) : id_(id) {}
int getId() const override { return id_; }
private:
int id_;
};
If I implement a function to iterate over std::vector<std::unique_ptr<Foo>>
, it looks like
template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
for (; first != last; ++first)
std::cout << (*first)->getId() << std::endl;
}
But what if I also want to allow iterating over vectors of homogeneous type (e.g., std::vector<Bar>
) without rewriting the whole function (or possible others, of similar type)? I see two obvious possibilities:
1) Implement functions
template<class Type>
const Type & dereference(const Type &value) {
return value;
}
template<class Type>
const Type & dereference(const std::unique_ptr<Type> &value) {
return *value;
}
and replace
std::cout << (*first)->getId() << std::endl;
by
std::cout << dereference(*first).getId() << std::endl;
2) Implement functions
template<class Type>
int getId(const Type &value) {
return value.getId();
}
template<class Type>
int getId(const std::unique_ptr<Type> &value) {
return value->getId();
}
and replace
std::cout << (*first)->getId() << std::endl;
by
std::cout << getId(*first) << std::endl;
Option 1) seems like a general possibility to treat references of type Type &
(or const Type &
) and std::unique_ptr<Type>
(or even Type *
or const Type *
) uniformly. However, I have not seen this being much used in production code. Is this a common pattern to avoid code duplication? Or are there better ways to handle this?
Aucun commentaire:
Enregistrer un commentaire