How to implement function with vector of derived c

2019-07-20 08:53发布

问题:

(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

回答1:

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;
}


回答2:

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.