Matthias -4 years ago 199
C++ Question

Convert array of pointers of derived class to array of base class pointers

Consider an inheritance hierarchy like this:

``` A / \ B1 B2 \ / C | D ```

Realized in C++ like so:

``````class A {
public:
A() {};
virtual ~A() = 0;
double a;
};

A::~A() {};

class B1 : virtual public A {
public:
B1() {}
virtual ~B1() {}
double b1;
};

class B2 : virtual public A {
public:
B2() {}
virtual ~B2() {}
double b2;
};

class C : public B1, public B2 {
public:
C() {}
virtual ~C() {}
double c;
};

class D : public C {
public:
D() {}
virtual ~D() {}
double d;
};
``````

Now, obviously I can do something like this:

``````D *d = new D();
A *a = (A*) d;
D *d_down = dynamic_cast<D*>(a);
assert(d_down != NULL); //holds
``````

However, I can't seem to figure out how to get same behavior using arrays. Please consider the following code sample to see what I mean by that:

``````D *d[10];
for (unsigned int i = 0; i < 10; i++) {
d[i] = new D();
}

A **a = (A**) d;
D *d_down = dynamic_cast<D*>(a[0]);
assert(d_down != NULL); //fails!
``````

So my questions would be:

• Why does to above assertion fail?

• How can I achieve the desired behavior?

• I noticed, by chance, that the dynamic_cast above works if I remove the double fields from classes A through D. Why is that?

The problem is, that `(A*)d` is not numerically equal to `d`!

See, you have an object like

``````+-----------------+
| D:              | <----- d points here
| D vtable ptr    |
| +-------------+ |
| | A:          | | <----- but (A*)d points here!
| | A vtable ptr| |
| | ...         | |
| +-------------+ |
| +-------------+ |
| | B:          | |
| | ...         | |
| +-------------+ |
| +-------------+ |
| | C:          | |
| | ...         | |
| +-------------+ |
| ...             |
+-----------------+
``````

When you cast a `D*` to `A*`, via `static_cast` or `dynamic_cast`, the compiler will inject the necessary arithmetic for you.

But when you cast it via `reinterpret_cast`, or cast a `D**` to `A**`, which is the same thing, the pointer will keep its numeric value, because the cast does not give the compiler the right to dereference the first layer to adjust the second layer.

But then the pointer will still point at D's vtable, not A's vtable, and therefore won't be recognized as A.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download