Search code examples
c++castingopaque-pointers

Upcasting opaque pointer


I'm trying to use pimpl idiom. In particular, the implementation class would implement another interface:

// public_class.h
class PublicClass
{
public:
    /* public interfaces here */
private:
    class _PublicClass_impl;
    friend class _PublicClass_impl;
protected:
    _PublicClass_impl * const _impl;
};

// public_class.cpp
class PublicClass::_PublicClass_impl : public SomeInterface
{
    friend class PublicClass;
    /* all sort of stuff ... */
};

My question is, what casts can be used in the following situation?

// some_other_class.h
class SomeOtherClass : private PublicClass
{
    void some_function()
    {
        // definition of _PublicClass_impl is unknown
        // thus, _impl is opaque

        SomeInterface * interface = dynamic_cast<SomeInterface *>(_impl); //??
        /* more code ... */
     }
};

Would dynamic_cast work fine in this case? Are there any other types of cast that can be used in this case?


Solution

  • As far as I can tell, there isn't a gaurenteed way to do what you want. A reinterpret_cast or c-style cast might work (the behavior is unspecified), but the others are all undefined behavior when it lets you compile it at all.

    5.2.7.2 of n3242 (I know it's not the official standard, but it should be close) says about dynamic_cast(v),

    If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. If T is an lvalue reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. If T is an rvalue reference type, v shall be an expression having a complete class type, and the result is an xvalue of the type referred to by T.

    So dynamic_cast doesn't work.

    static_cast doesn't work since there aren't any valid conversion defined between the two types.

    5.2.10.7 says about reinterpret_cast(v),

    A pointer to an object can be explicitly converted to a pointer to a different object type.69 When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast(static_cast(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

    so a reinterpret_cast might work.

    And finally, not using a cast doesn't work because the compiler doesn't know about the relationship between the types.