Home > Software design >  Downcasting pointer to pointer
Downcasting pointer to pointer

Time:12-16

I'm learning polymorphism in C and I can't downcast a pointer to a pointer. I have a class Base and a class Derived that extends Base. And I want to do a pool of Derived objects using a function Base **derivedFactory(size_t size). I tried doing Base** array = new Derived*[size]; but the compiler says that it can't convert from Derived** to Base**. So I tried the next:

Base **derivedFactory(size_t size)
{
    Base* array = new Derived[size];
    
    for (size_t idx = 0; idx < size;   idx)
    {
        Derived derived = Derived();
        array[idx] = derived;
    }
    
    Base** arrayBase = &array;
    
    return arrayBase;
}

And it compiles. But then when I want to access all Derived objects the main.cc throws a Segmentation fault (core dumped). It executes hello(cout) but then it throws before ending the first iteration of the loop.

Could you please help me?

Main.cc

#include "main.ih"

int main()
{
    Base **bp = derivedFactory(10);

    for (size_t idx = 0; idx <= 10;   idx)
    {
        bp[idx]->hello(cout);
        cout << "Not printing\n";
    }
}

Class Base:

class Base
{
    private:
        virtual void vHello(std::ostream &out)
        {
            out << "Hello from Base\n";
        }
    public:
        void hello(std::ostream &out)
        {
            vHello(out);
        }
};

Class Derived:

class Derived : public Base
{
    std::string d_text;

    private:       
        void vHello(std::ostream &out) override
        {
            out << d_text << '\n';
        } 

    public:
        Derived()
        {
            d_text = "hello from Derived";
        }
        
        virtual ~Derived()
        {}
};

Thank you!

CodePudding user response:

There are multiple fundamental problems with the shown code.

   Base* array = new Derived[size];

This creates an array of Derived objects. This kind of an array in C is represented by a pointer to the first value in array. In this case this would be a Derived *, which is what you get from new.

It is valid in C to downcast a pointer to a derived class into a pointer to a base class.

But that's it. That's all you get.

That doesn't mean that a pointer to the first derived object in an array can be downcasted to a pointer to a base class, and then the pointer to the base class be used to access every derived object in the actual array. Pointers don't work this way in C . Attempting to access any other object besides the first object, that the pointer points to, is undefined behavior. This is the first fundamental problem with the shown code.

Base** arrayBase = &array;

array is an object that's declared as a local object in this function. When this function returns, array gets destroyed, like any other variable declared in this function. It will be destroyed. It will be no more. It will cease to exist. It will pine for the fjords. It will become an ex-object.

The shown code attempts to take an address of this object and return it from this function. After the function returns this pointer becomes a pointer to a destroyed object, and any attempt to access it will be undefined behavior.

Doing this correctly requires a completely different approach. Instead of using new to create an array of derived objects, this should be done by using new to create an array of pointers to the base object. Then, each pointer gets initialized, individually, by newing an individual derived object, something like:

 Base **array = new Base *[size];

 // ...

 array[i] = new Derived{};
  • Related