gbombay
gbombay

Reputation: 21

reference to a std::vector of derived class pointers as input parameter to a function

First of all I'd like to apologize if there's another question like this one and I didn't find it. I've been trying but since the problem is quite specific I couldn't find one.

Now, the problem. I have a Base class and a Derived class (say BNode and DNode ), and I have a std::vector of BNode*. I have also a function which receives a reference to a vector of these pointers. I'm having trouble when trying to pass a std::vector of pointers to derived objects as a parameter to this function:

class BNode
{
};

class DNode : public BNode
{
};

class Other
{
function(std::vector<BNode*>& inputVector) { } 
}

When trying to pass a vector of pointers to the derived class, the error I'm receiving from VS is:

1> error C2664: 'Other::function' : cannot convert parameter 1 'std::vector<T>' to 'std::vector<T> &'
1>        with
1>        [
1>            T=DNode *
1>        ]
1>        and
1>        [
1>            T=BNode *
1>        ]

Thanks beforehand.

Upvotes: 2

Views: 2651

Answers (6)

Fr&#233;d&#233;ric Hamidi
Fr&#233;d&#233;ric Hamidi

Reputation: 262939

C++ doesn't support covariance in templates. An std::vector<DNode*> cannot be assigned to an std::vector<BNode*> even if DNode derives from BNode.

For your code to work, you should only declare vectors of pointers to BNode and populate them with pointers to DNode as needed.

Upvotes: 1

0xF
0xF

Reputation: 3708

std::vector is not covariant.

In general, you should not pass a vector of DNode * as a vector of BNode *. If function adds or replaces pointers to a subclass of BNode different from DNode, you would get non-DNode pointers in your DNode * vector.

You better change your types as explained in the other answers.

But contrary to what other answers say, it is possible to pass a vector of DNode * if function only reads the vector. To mark it so, change its signature to accept a const reference. Then you can pass your DNode * vector as follows:

function(reinterpret_cast<const std::vector<BNode *> &>(vec));

reinterpret_cast is generally dangerous and you should avoid it unless you know very well what you are doing. Here, you are circumventing the C++ type system to treat a vector of DNode * as a vector of BNode *. Raw pointers are primitive types with the same binary representation regardless of the pointed-to type. Therefore the vectors of both pointer types are runtime compatible.

Upvotes: 1

Bart van Ingen Schenau
Bart van Ingen Schenau

Reputation: 15768

Unfortunately, what you want is not possible in C++, because vector<BNode*> and vector<DNode*> are considered to be unrelated types (even though there is a clear relation between BNode and DNode).

Consider the following code:

class BNode
{
};

class DNode : public BNode
{
};

class XNode : public BNode
{
};

void function(std::vector<BNode*>& inputVector) 
{
  inputVector.push_back(new XNode); // This will work, as XNode derived from BNode
} 

int main()
{
  std::vector<DNode*> vec;

  function(vec); // Suppose this would work
  // Then now, vec would contain a pointer to the unrelated class XNode!!
}

Upvotes: 1

clstrfsck
clstrfsck

Reputation: 14829

I suspect you are probably calling Other::function something like this:

std::vector<DNode *> v;
// put stuff into v
Other o;
o.function(v);

Which won't compile, as std::vector<DNode *> is a distinct type to std::vector<BNode *>.

What may be suitable is:

std::vector<BNode *> v;
// You can put DNode * items into v
Other o;
o.function(v);

Upvotes: 1

ereOn
ereOn

Reputation: 55736

Your problem is that even if DNode derives from BNode, std::vector<DNode*> doesn't derive from std::vector<BNode*>.

Therefore, the compiler does not know how to convert from one type to the other.

You might however do:

std::vector<BNode*> bnode_list;
std::vector<DNode*> dnode_list(bnode_list.begin(), bnode_list.end());

Upvotes: 4

Manoj R
Manoj R

Reputation: 3247

This is because vector< Bnode* > and vector< Dnode* > do not have any parent-child relation. They are different objects.

I guess you have created a vector like std::vector< DNode* > dnodevec; Instead you can create std::vector< BNode* > dnodevec; Being the vector of base class pointers you can safely insert any DNode type pointer in the vector.

Upvotes: 3

Related Questions