2

Hello everyone and thank you for looking. This is a follow up to the original question posted here.

I have a base class that I define thusly:

class DrawableShape
{
public:
    virtual HRESULT DrawShape(ID2D1HwndRenderTarget* m_pRenderTarget)
    {
        return S_OK;
    }
};

I have two classes that extend this class, both are similar, so I'm listing one:

class MyD2DEllipse : public DrawableShape
{
private:
    D2D1_ELLIPSE data;
public:
    MyD2DEllipse();
    HRESULT DrawShape(ID2D1HwndRenderTarget* m_pRenderTarget);
};

The DrawShape function is implemented like this:

HRESULT MyD2DEllipse::DrawShape(ID2D1HwndRenderTarget* m_pRenderTarget)
{
    HRESULT hr = E_FAIL;
    ID2D1SolidColorBrush* m_pBrush;
    hr = m_pRenderTarget->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::OrangeRed),
                &m_pBrush
                );
    m_pRenderTarget->DrawEllipse(&data, m_pBrush, 10.f);
    return hr;
}

I want to draw a random number of ellipses and rectangles to the screen, so I first find out those random numbers, create an array of DrawableShape with that size (since I can't allocate objects dynamically in C++), replace the parent objects with the child objects, and then call the draw function on the array, randomly again. Here's what my code looks like:

    HRESULT Demo::OnRender()
    {
        HRESULT hr = S_OK;
        hr = CreateDeviceResources();

        if (SUCCEEDED(hr))
        {
            m_pRenderTarget->BeginDraw();
            m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
            m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

            // Decide on # of primitives
        randEllipse = 1 + (rand() % 5);
        randRectangle = 1 + (rand() % 5);
        totalPrimitives = randEllipse + randRectangle;

        DrawableShape *shapes;
        shapes = new MyShape[totalPrimitives];

        for (int i=0; i<randEllipse; i++)
        {
            MyEllipse ellipse1;
            shapes[i] = ellipse1;
        }
        for (int i=randEllipse; i<(randEllipse + randRectangle); i++)
        {
            MyRectangle rect1;
            shapes[i] = rect1;
        }

        for (int i=0; i<totalPrimitives; i++)
        {
            hr = shapes[i].DrawMyShape(m_pRenderTarget);
        }
        hr = m_pRenderTarget->EndDraw();
    }
}

That should've worked, but it doesn't. Also, after writing this out, I realize that I'm better off creating the array in some sort of init function, and calling the draw on the array in the OnRender function. Please help!!


EDIT: Okay I've got the shapes working with pointers, the problem is the construction of the array. So I have something like this:

    MyD2DRectangle rect1;
    MyD2DEllipse ell1;

    DrawableShape *shape1 = &rect1;
    DrawableShape *shape2 = &ell1;
    shape1->DrawShape(m_pRenderTarget);
    shape2->DrawShape(m_pRenderTarget);

That seems to work by itself. How can I create the array of DrawableShape without slicing?

Community
  • 1
  • 1
Freakishly
  • 1,533
  • 5
  • 32
  • 61

1 Answers1

4

shapes is an array of MyShape instances. When you say shapes[i] = ellipse1; or shapes[i] = rect1;, you are losing the subclass data as part of this assignment, which is known as slicing in C++.

As such, each call to shapes[i].DrawMyShape(m_pRenderTarget); is just returning S_OK as defined in MyShape.

In order to properly use polymorphism in C++, you need to use pointers or references to MyShape instances (usually allocated using new). If you are not allowed to do this (homework?), then you need to find a way to do this without polymorphism.

Community
  • 1
  • 1
James
  • 5,355
  • 2
  • 18
  • 30
  • Okay, slicing makes perfect sense. Now, while I am allowed to use pointers, I'm not exactly comfortable around them. Could you suggest syntactic examples/share some links on the correct usage? Thanks James. – Freakishly Jan 20 '11 at 22:01
  • This link will probably explain it better than I can. http://www.cplusplus.com/doc/tutorial/dynamic/ – James Jan 20 '11 at 22:05
  • Right, as Mark Ransom said, instead of using an array of `MyShape`, make `DrawableShape **shapes = new MyShape*[totalPrimitives]`. Then you have an array of `MyShape*`, not an array of `MyShape`. – James Jan 20 '11 at 23:45
  • Lol, just figured that out, thanks.... I'll edit the question with my final answer once I have it. I'm marking your answer as the right one. Thanks for all the help, James :) – Freakishly Jan 20 '11 at 23:49
  • No problem. I remember struggling with pointers once. It will pass. Just keep working at it. :) – James Jan 20 '11 at 23:51
  • btw, I used DrawableShape* shapes[totalPrimitives]; instead of DrawableShape **shapes = new DrawableShape*[totalPrimitives]; Both statements work, so what's the difference? – Freakishly Jan 20 '11 at 23:54
  • The first allocates the memory on the local stack, whereas the second is allocated to the heap. Yours is probably the better solution for how it was being used. – James Jan 21 '11 at 00:00
  • Aaaah, correction. I used DrawableShape* shapes[2]; When I replace that with DrawableShape* shapes[totalPrimitives]; I get an error saying "expected constant expression, cannot allocate an array of constant size 0. 'shapes' unknown size." Looks like I'll be allocating to the heap. – Freakishly Jan 21 '11 at 00:31