1

How we could cast an Array of base class pointer to an array of derived class pointer. The following code show an simple example of what i'am trying to do :

class CBaseClass
{
    public :
        int CommonValue;
};

class CFirstItem : public CBaseClass
{
    public :
        int firtValue;      
};

class CSecondItem : public CBaseClass
{
    public :
        int secondValue;        
};

class CThirdItem : public CBaseClass
{
    public :
        int thirdValue;     
};


class Manager
{
    public :
        Manager()
        {
            for (unsigned int index = 0; index < 5; ++index)
            {
                m_firstItem[index] = new CFirstItem();
            }
            for (unsigned int index = 0; index < 10; ++index)
            {
                m_secondItem[index] = new CSecondItem();
            }
            for (unsigned int index = 0; index < 12; ++index)
            {
                m_thirdItem[index] = new CThirdItem();
            }
        }

    private :
        CBaseClass* m_firstItem[5];
        CBaseClass* m_secondItem[10];   
        CBaseClass* m_thirdItem[12];    
};

My main question here is how could i cast from CBaseClass to an CFirstClass or CSecondClass, i tried

CFirstClass* wFirstClass = static_cast<wFirstClass*>(m_firstItem);

And that doesn't seems to work, there is any way to how this cast should be made ?

3
  • 1
    if you are using polymorphism, you should specify the destructor of the base class as virtual - virtual ~CBaseClass() = default;. Also - read about static_cast and dynamic_cast Commented Sep 27, 2017 at 18:32
  • 2
    I suppose the second and third loops are inserting element in m_secondItem and m_thirdItem arrays respectively (not in m_firstItem as in your example). But if m_firstItem array contains only pointers on CFirstItem and m_secondItem pointers on CSecondItem and so on, why don't you have pointers of the good type CFirstItem* m_firstItem[5] etc... in which case you don't need any cast. Commented Sep 27, 2017 at 19:52
  • Yes you are right i will edit it... Commented Sep 27, 2017 at 19:54

2 Answers 2

3
CFirstClass* wFirstClass = static_cast<wFirstClass*>(m_firstItem);

is wrong since w_firstItem decays to CBaseClass** in the above expression.

You will be better off if you can design your program such that you don't need to cast. If you must cast, you will need to use dynamic_cast.

CFirstClass* wFirstClass = dynamic_cast<CFirstClass*>(m_firstItem[0]);
if ( wFirstClass )
{
   // Use the pointer.
}
else
{
   // Deal with other cases
}

If you need to cast every pointer in m_firstItem, you need to use a loop.

for ( auto item : m_firstItem )
{
   CFirstClass* wFirstClass = dynamic_cast<CFirstClass*>(item);
   if ( wFirstClass )
   {
      // Use the pointer.
   }
   else
   {
      // Deal with other cases
   }
}

Update

@RemyLebeau makes a good point. You should use dynamic_cast only if m_firstItem holds pointers to different sub-types of CBaseClass. In your posted code, since it holds only pointers to CFirstClass, it's ok to use static_cast instead of dynamic_cast:

CFirstClass* wFirstClass = static_cast<CFirstClass*>(m_firstItem[0]);

The loop version can similarly use static_cast<CFirstClass*>(item).

Sign up to request clarification or add additional context in comments.

4 Comments

Since m_firstItem[] contains only CFirstItem pointers, the dynamic_cast should be replaced with static_cast. Same with the other arrays. Using dynamic_cast would make sense only if the arrays are merged together into a single array that can hold pointers to different derived types.
@RemyLebeau, makes sense.
@RSahu Actually, no. Not What RemyLebeau said but OP's example. It doesn't make sense to use an array of CBaseClass* pointers if you're only every going to use it for CFirstItem* pointers.
@n.caillou, we can only speculate why the OP chose to use an array of CBaseClass* and chose to store only pointers to objects of type CFirstItem in it. I see that they could have used an array of CFirstItem* and obviated the need for casting in the first place.
2

You can't simply type-cast an array of base pointers to an array of derived pointers. The pointers will not be pointing at the correct addresses. If you need an array of derived pointers, you have to create a separate array and type-cast the source items correctly, eg:

CFirstClass* wFirstClass[5];
for (int i = 0; i < 5; ++i)
    wFirstClass[i] = static_cast<CFirstClass*>(m_firstItem[i]);

Same with the other arrays:

CSecondClass* wSecondClass[10];
for (int i = 0; i < 10; ++i)
    wSecondClass[i] = static_cast<CSecondClass*>(m_secondItem[i]);

CThirdClass* wThirdClass[12];
for (int i = 0; i < 12; ++i)
    wThirdClass[i] = static_cast<CThirdClass*>(m_thirdItem[i]);

4 Comments

@n.caillou: If you type-cast a CBaseClass*[] array itself to a CFirstClass*[] array, the object pointers WILL NOT be correct. They will still be pointing at CBaseClass objects in memory, and will be misinterpretted as CFirstClass objects when accessed from the casted array. Think of what would happen if you have a CBaseClass* pointer misinterpreted as a CFirstClass* pointer and you try to access the firstValue member. It won't work, it will actually be accessing CommonValue instead (if you are lucky). You need a proper CFirstClass* pointer to a real CFirstClass object.
Oh, I see. If VMT pointers were introduced in the middle of the hierarchy.
@n.caillou: the issue I have described has nothing to do with VMTs, which only apply to virtual methods, not to data members. Data members are just positive offsets from the start of the declaring class, and at negative offsets from derived classes. So having proper pointers to proper object types is important so the compiler can calculate the offsets correctly. Accessing CommonValue from a CBaseClass* pointer is different than accessing it from a CFirstClass* pointer. firstValue can't be accessed from a CBaseClass* pointer, only a CFirstClass* (or derived) pointer.
@n.caillou: You need to read up on how polymorphic classes are actually laid out in memory, and how polymorphic pointers actually work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.