RHSmith159
RHSmith159

Reputation: 1592

C++ Cast sub-sub class to base

With the classes below:

enum class OBJECT_TYPE {TYPE_1, TYPE_2, TYPE_3};

class BaseClass {
public:
    BaseClass();
    virtual ~BaseClass();
    OBJECT_TYPE getObjectType() { return m_objectType; }
protected:
    OBJECT_TYPE m_objectType;
}

class ChildClass : public BaseClass {
public:
    ChildClass();
    virtual ~ChildClass();
    virtual void init() = 0;
protected:
    // some other variables
}

class ChildChildClass : public ChildClass {
public:
    ChildChildClass ();
    ~ChildChildClass ();
    void init() override { m_objectType = OBJECT_TYPE::TYPE_3 }
private:
    // some other variables
}

In a separate part of the code base, how would I cast a void* to a ChildChildClass instance to a BaseClass* such that I can call getObjectType() to determine which type of object it points to. I'm currently doing this:

(someOtherMethod() returns a void* to a ChildChildClass)

void* initialPointer = someOtherMethod();
BaseClass* basePointer = static_cast<BaseClass>(initialPointer);
if (basePointer->getObjectType() == OBJECT_TYPE::TYPE_3) {
    ChildChildClass* childChildPointer = static_cast<ChildChildClass*>(basePointer);
}

I think I may be misunderstanding casting pointers when using inheritance, as I'm getting nonsense values for the returned objectType so any advice or info would be appreciated!

Upvotes: 2

Views: 165

Answers (3)

R Sahu
R Sahu

Reputation: 206747

I would recommend using dynamic_cast.

// This is risky but I assume you know what you are doing.
// BTW, you are using static_cast<BaseClass>. That is not correct.
BaseClass* basePointer = static_cast<BaseClass*>(initialPointer);

// Now use dynamic_cast.
ChildChildClass* childChildPointer = dynamic_cast<ChildChildClass*>(basePointer);

if ( childChildPointer != nullptr)
{
   // Use childChildPointer.
}
else
{
   // Do something different.
}

It will be better if someOtherMethod can be modified to return a BaseClass*.

BaseClass* basePointer = someOtherMethod();

Then, rest of the code is unlikely to be a problem.

Upvotes: 0

Michael Kenzel
Michael Kenzel

Reputation: 15951

I'll ignore the numerous issues with such a design and just assume that you have a very good reason (i.e. can't change the design) for wanting to do what you're asking for. If you know that someOtherMethod() returns a void* that points to a ChildChildClass object, then you can first static_cast that void* to a ChildChildClass* and then either perform an explicit upcast to a BaseClass* or just use that ChildChildClass* as a BaseClass* since it can implicitly be converted anyways (there should be no need to perform an upcast just for the purpose of calling the method since ChildChildClass publicly derives from BaseClass):

ChildChildClass* initialPointer = static_cast<ChildChildClass*>(someOtherMethod());
BaseClass* basePointer = static_cast<BaseClass*>(initialPointer);

However, based on your code above, I am led to believe that you don't actually know that someOtherMethod() returns a pointer to a ChildChildClass object. Otherwise, why would you have to check whether it does before casting to ChildChildClass*? If you don't know the concrete type of object that the void* returned by someOtherMethod() points to, then there is no way to perform the cast you want to perform here (because there is know way of knowing what should actually be cast into what). One solution would be to change someOtherMethod() to always return a BaseClass* or at least a void* that you know for sure always points to a BaseClass object…

Upvotes: 3

Christophe
Christophe

Reputation: 73637

You should use reinterpret_cast<> for casting from a void* :

 BaseClass* basePointer = reinterpret_cast<BaseClass*>(initialPointer);

But be extremely careful ! This is UB if the initialPointer would not point to an object of the correct type !

Additional recommendation:

For the down-casting, a safer approach would be to use dynamic_cast<>:

ChildChildClass* childChildPointer = dynamic_cast<ChildChildClass*>(basePointer);
if (! childChildPointer) 
    cout << "Something wrong happened !" <<endl; 

Upvotes: 1

Related Questions