Convert vector<DerivedObject*> to vector<Object*>

Hello,

I'm trying to send a vector<DerivedObject*> to a function that takes in a vector<Object*> where DerivedObject inherits Object. But when I compile the following program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <vector>
using namespace std;

class Object {};
class DerivedObject : public Object {};

vector<DerivedObject*> create_derived_objects()
{
  return vector<DerivedObject*>();
}

void use_objects(vector<Object*> const& objects) {}

int main()
{
  vector<DerivedObject*> const& derived_objects = create_derived_objects();

  use_objects(derived_objects);

  return 0;
}


I get the following compiler error:

invalid initialization of reference of type ‘const std::vector<Object*, std::allocator<Object*> >&’ from expression of type ‘const std::vector<DerivedObject*, std::allocator<DerivedObject*> >’


I may have found a solution by using reinterpret_cast:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
  vector<DerivedObject*> const& derived_objects = create_derived_objects();

  vector<Object*> const& objects =
    reinterpret_cast< vector<Object*> const& >(derived_objects);

  use_objects(objects);

  return 0;
}


This compiles without errors, but I'm not sure if using reinterpret_cast is the best solution. Is there a better solution?

Thanks.
This would be a bad cast. It might work if you're lucky, but there's no guarantee it will work. You can only cast DerivedObject* to Object*. You cannot [safely] cast a container that holds those pointers.

The reason for this is because the casted pointer may not point to the same address. For example:

1
2
3
4
DerivedObject* foo = &someobject;
Object* bar = foo;

if(bar == foo)  // <- this is not guaranteed to be true! 


since the casted pointer is not guaranteed to be equal to the original pointer, a container holding the original pointers being reinterpretted as casted pointers could result in all the pointers being bad/corrupt.


Basically: you can't do this.

The reason for this is because the casted pointer may not point to the same address. For example:

1
2
3
4
DerivedObject* foo = &someobject;
Object* bar = foo;

if(bar == foo)  // <- this is not guaranteed to be true!  



since the casted pointer is not guaranteed to be equal to the original pointer, a container holding the original pointers being reinterpretted as casted pointers could result in all the pointers being bad/corrupt.


Well, I am not totally sure about the specification when comparing pointers, but it should be fine to cast a single DerivedObject to an Object. A DerivedObject is an Object. The pointers should be equal. It just may be undefined to compare them, since they do not point into an array.

You can not safely use such cast when accessing a container though. In you have a pointer into a container of DerivedObjects, and you cast it to a pointer to Object, any pointer arithmetic with it as an Object pointer will be incorrect since Object and DerivedObject are probably not the same size. Any arithmetic will add or subtract the wrong byte offset into the array. This probably wouldn't be the wrong element, it would actually point into part of an element as if it was the start of a different element; very bad.

That is not what the original poster is doing here. You don't have a container of Objects or DerivedObjects, you have a container of pointers to Objects, and a container of pointers to DerivedObjects. Pointers should be the same size, so a reinterpret_cast may work. It can be implementation defined though, and is not recommended.

The proper way to do this is to not use a container of DerivedObject* in the first place. Your function wants a container of Object pointers, so when you create your DerivedObjects and populate the vector, just use a vector of Object*, and cast the DerivedObject* to Object* when you insert them. It is common to have containers of pointers to a base class, but actually put pointers of derived classes into it, and use virtual function calls to get the desired behavior for each object.

So, do you have a good reason to actually need a vector of DerivedObject pointers?

In the unlikely event that you actually do, then you could possibly implement use_objects() as a template function, but that would require careful implementation; it is easy to make it take any type of pointer, but it is probably only meant to work with classes descended from Object.
Object and DerivedObject point to the same location in this case. They wouldn't in the case of multiple inheritance. You could create a container type that uses void pointers behind the curtains and allows type-safe interfaces for many different types. It would contain only pointer to some dynamically allocated array and converting it would be fast. Void pointers are guaranteed to be able to hold all kinds of pointer values. But this is probably way off of your case.

Basically, both Disch and jimc have given you better instructions.

Regards
Use a function template instead:

1
2
template <class T>
void use_objects(vector<T*> const& objects) {}


Now your function can accept vector<DerivedObject*> too.
I know this is an ugly workaround, it gives an ugly error if you pass it something that does not derive from Object*, but at least it works.

Generic type covariance/contravariance is not supported by C++ directly.
Language I know of that support it are C# 4.0 (declaration site covariance specification), Java (use site covariance specification) and Scala (both).

Example in Scala:

1
2
3
4
class DerivedObject extends Object {...}
def useObjects(objects: Vector[Object]) = {...}
val vector = new Vector[DerivedObject]()
useObjects(vector)  // compiles and works as desired 


Example in Java:
1
2
3
4
class DerivedObject extends Object {...}
public void useObjects(ArrayList<? extends Object> objects) {...}
val vector = new ArrayList<DerivedObject>(5)
useObjects(vector)  // compiles and works as desired 


Last edited on
Object and DerivedObject point to the same location in this case.


I want to note that even if this is true in this instance, it is not guaranteed to be true, and therefore C++ does not allow you do to this. Forcing it with reinterpret_cast is unsafe because there's no guarantee it will work -- even if it does happen to work in this instance.

You could create a container type that uses void pointers behind the curtains and allows type-safe interfaces for many different types


Void pointers would do nothing to help, they would only make it worse.

The problem persists that an Object* doesn't necessarily equal a DerivedObject* even if they point to the same object. Casting them to a void* does nothing to solve that problem. All that would do is completely destroy type safety and force all sorts of additional casts.


Is there any reason this function needs to take a vector? Passing around vectors generally isn't something I would do. Maybe rethink the design so that you only need to pass individual pointers.




EDIT: skipped over jimc's post...

jimc wrote:
Well, I am not totally sure about the specification when comparing pointers, but it should be fine to cast a single DerivedObject to an Object. A DerivedObject is an Object.

This is true. There is no problem with casting a DerivedObject* to an Object*

The pointers should be equal


Yes, technically, I was wrong before. Doing a comparison between types does in fact guarantee they will always be equal when compared with the == operator. However the raw pointer still points to something else. This can be exposed by either casting them to void* and comparing them (in which case they won't match), or simply outputting the pointers (in which case you can see they point to different addresses).


Here's an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;

class A { public: virtual ~A() {} };
class B { public: virtual ~B() {} };
class C : public A, public B { };

int main()
{
    C obj;
    A* a = &obj;
    B* b = &obj;
    C* c = &obj;

    cout << a << '\n' << b << '\n' << c << endl;

    if(b == c)      cout << "This will be true (b==c)." << endl;
    if(a == c)      cout << "This will be true (a==c)." << endl;

    void* va = a;
    void* vb = b;
    void* vc = c;

    if(vb != vc)    cout << "This might be true (vb!=vc)" << endl;
    if(va != vc)    cout << "This might be true (va!=vc)" << endl;

    cin.get();
}


On my machine it prints this:


0047FE00
0047FE04
0047FE00
This will be true (b==c).
This will be true (a==c).
This might be true (vb!=vc)


Notice the 3 pointers at the start -- they point to different addresses.
Last edited on
Thank you all for your comments. You've convinced me that using reinterpret_cast is very unsafe. It works now, but the risk that it may not in the future is too high.

I don't HAVE TO return a vector<DerivedObject*>; I could instead return a vector<Object*> in my "create" function. But in my actual program (not the sample code) it makes more sense to me to return a vector of the derived objects. I suppose I could also avoid passing vectors altogether, but again, for my actual program it makes sense.

So what is my actual program? I have a base class Genotype and a derived class HybridGenotype. I have a function that takes in two Genotypes and returns a vector<HybridGenotype*> containing several recombinants (hybrids). I also have a function that takes in a vector<Genotype*> and measures their "fitness" (measuring fitness one by one is inefficient with the system I'm using, which is why I need to pass a list of Genotypes). I need to create several hybrids and measure their fitness. I suppose I could have the "create_hybrids" function return a vector<Genotype*>, but returning a vector<HybridGenotype*> emphasizes that hybrids are being created.

Templates are one solution, as some of you mentioned, but I think templates add too much complexity to my simple problem. I think I'll settle with returning a vector<Genotype*> rather than a vector<HybridGenotype*>.
Topic archived. No new replies allowed.