2

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.

gbombay
  • 21
  • 1
  • 3
  • Sorry, I forgot the ' : public BNode' ... – gbombay Oct 13 '10 at 09:45
  • http://bytes.com/topic/c/answers/136191-passing-derived-class-object-array-place-base-class-object-array - See Andrew Koenig and Alf P. Steinbach say why it isn't allowed in C++ – DumbCoder Oct 13 '10 at 09:49
  • what's your question now? Would you like to understand the reason of this or are you looking for a solution? – Philipp Oct 13 '10 at 09:51
  • 1
    Duplicate question: http://stackoverflow.com/questions/114819/how-get-a-vectorderived-into-a-function-that-expects-a-vectorbase-as-argume – Fred Foo Oct 13 '10 at 09:57

6 Answers6

4

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());
ereOn
  • 53,676
  • 39
  • 161
  • 238
  • this is a very nice solution: the only suggestion that works nicely for constructor arguments as well – penelope Apr 24 '13 at 08:09
3

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.

Manoj R
  • 3,197
  • 1
  • 21
  • 36
1

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.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
1

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);
clstrfsck
  • 14,715
  • 4
  • 44
  • 59
1

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!!
}
Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
  • That is true in this case, would not apply if the vector were immutable. C++ is somewhat flawed in this regard, although if the purpose is to call some virtual method on every item, it is possible to do with for_each. – CashCow Oct 13 '10 at 10:23
0

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.

0xF
  • 3,214
  • 1
  • 25
  • 29