Question

#include<iostream>

struct I1
{ 
    virtual void nb1()=0;
    virtual ~I1(){}
};

struct I2
{ 
    virtual void nb2()=0;
    virtual void nb22()=0;
    virtual ~I2(){}
};

struct C12 : I1, I2
{
    virtual void nb1(){std::cout << "nb\n";}    
    virtual void nb2(){std::cout << "nb2\n";}    
    virtual void nb22(){std::cout << "nb22\n";}
};

int main()
{
    I2 * p2 = new C12; 
    I1 * p1 = reinterpret_cast<I1*>(p2);
    return 1;
}

Is there any contraindications to use a reinterpret_cast here ? Should I mandatory use dynamic_cast?

Is it ok ONLY if I1 and I2 are pure virtual ?

Was it helpful?

Solution

The reinterpret_cast is unsafe; you should always use dynamic_cast. It is irrelevant that I1 and I2 are pure virtual classes; as subobjects of C12 they have nonzero storage requirements. Indeed, in the following program:

int main() {
    I2 * p2 = new C12; 
    I1 * p1 = reinterpret_cast<I1*>(p2);
    std::cout << p2 << '\n';
    std::cout << p1 << '\n';
    std::cout << dynamic_cast<I1*>(p2) << '\n';
    p1->nb1();
}

the output is:

0x14de0c8
0x14de0c8
0x14de0c0   // !!!
nb2         // !!!

You may be thinking of the empty base optimization (1.8p5); but this does not apply to classes with virtual methods, which require a vptr.

OTHER TIPS

Is there any contraindications to use a reinterpret_cast here ?

Don't do that; it will give undefined behaviour.

Typically, the base sub-objects are stored at different locations within the complete object, so that cast will end up pointing to the wrong location. You might find that it "works" by accident with these empty base classes, since they might (or might not) end up at the same location; but you certainly can't rely on that behaviour.

Should I mandatory use dynamic_cast?

If you don't know the common derived type (C12) at compile time, then that's the only sensible option. Note that it requires polymorphic classes (which is the case here).

If you do know the common derived type, then you can convert via that using static_cast:

I1 * p1 = static_cast<C12*>(p2);

Note that the "upcast" from the derived class can be done implicitly; only the "downcast" from the base class needs an explicit cast.

Since the compiler might reserve some bytes for each of the two subobjects of C12 even if they have no members or base classes, and since then the addresses of those two subobjects are distinct, this can lead to problems. The standard just says that the result of that cast is unspecified (§5.2.10,7).

It's almost always bad idea to use reinterpret_cast.

Here you may do either dynamic_cast or double static_cast (via base class).


From ABI point of view your C12 is:

struct C12 {
    I1 parent1;
    I2 parent2;
};

C12 obj;

Now you've get pointer to inner obj.parent2, which is not obj.

If you have an object x of type C12 and have three pointers pointing to it like in:

C12 x;
C12 *pA = &x;
I1  *pB = &x;
I2  *pC = &x;

then the pointers pA, pB and pC are not necessarily equal. So you can't just reinterpret_cast back and forth between pA, pB and pC. You can safely static_cast or dynamic_cast between pA and pB and between pA and pC. So to get an I1* from an I2* you need to cast your p2 first to C12*, then to I1*. Pick the line you like most:

I1 * p1 = static_cast<C12*>(p2);
I1 * p1 = dynamic_cast<C12*>(p2);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top