(Related to a previous unanswered question I asked). I want to implement a function which can be called only with vectors of related classes as parameter.
For eq
if we have
class A;
class B: public A;
class C: public A;
class D
then it should be possible to call function with vector<A*>,vector<B*> or
vector <C*> but not vector <D*>
Any suggestions
I guess you already tried to create a method like
void doSomething(std::vector<A*>& things)
{
}
and tried do pass
std::vector<B*> bList = ...;
doSomething(bList);
right?
Why does the compiler complain? Because it would not make sense. Consider that doSomething() tries to do
things.push_back(new C());
This cannot work as "things" is actually a std::vector<B*>
. However, if it were std::vector<A*>
, push_back would work.
So what can we learn from this? What you're trying only makes sense if you only read from the vector, however, vector is not a read-only container.
A simple wrapper shows a possible solution (the wrapper can be adjusted to your needs, of course). However, I have to point out that the use of virtual methods might lead to performance penalties.
class A {};
class B : public A {};
template <class Base>
class AbstractVectorWrapper
{
public:
virtual size_t size() const = 0;
virtual Base* getElementAt(int index) const = 0;
};
template <class Base, class Derived>
class VectorWrapper : public AbstractVectorWrapper<Base>
{
private:
std::vector<Derived*> m_vector;
public:
explicit VectorWrapper(std::vector<Derived*> const& vector)
: m_vector(vector)
{
}
virtual size_t size() const
{
return m_vector.size();
}
virtual Base* getElementAt(int index) const
{
return m_vector[index];
}
};
void doSomething(AbstractVectorWrapper<A> const& wrapper)
{
for (size_t i=0;i<wrapper.size();i++)
{
A* a = wrapper.getElementAt(i);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<A*> as;
std::vector<B*> bs;
doSomething(VectorWrapper<A,B>(bs));
doSomething(VectorWrapper<A,A>(as));
return 0;
}
Is duck-typing good enough for you? Consider this code
template <class T>
void my_function (std::vector <T*> const &values) {
// Use features of A* here
}
This will fail to compile if you use features that pointers to T
do not support. By using features of A
I think it should be guaranteed that pointers to B
and C
will also work as expected. However, it would be possible to call this function with vectors of D *
, provided D
's interface complies with what my_function
tries to do.