In
BouncingBall::BouncingBall()
{
Initialise(0, 0, 0, 0, 0);
m_pRenderer = NULL;
}
m_pRenderer
is explicitly NULLed. It is allocated no storage.
However this looks like it should be corrected in
void BouncingBall::Initialise(int m_PositionX, int m_PositionY, int m_DirectionX, int m_DirectionY, ASCIIRenderer* m_pRenderer){
}
But BouncingBall::Initialise
has not been fully implemented and discards the provided renderer. m_pRenderer
is still NULL.
Later in
void BouncingBall::Render()
{
if (m_pRenderer == NULL){
CHAR_INFO ball;
ball.Char.AsciiChar = 0;
ball.Attributes = BACKGROUND_RED;
m_pRenderer->SetPixel(m_PositionX, m_PositionY, ball);
}
}
m_pRenderer
is tested to ensure that it still points at nothing and is then invoked. This is the reverse of the logic OP needs, and SetPixel
is called on a NULL pointer. Boom.
Solution: Fully implement BouncingBall::Initialise
and replace the test in BouncingBall::Render
for is NULL if (m_pRenderer == NULL)
with is NOT NULL if (m_pRenderer != NULL)
Though a better approach is to embrace RAII and not have an initialize function in the first place. Do it in the constructor. Test for a valid renderer in the constructor and throw an exception to abort construction if invalid.
This way there is always a valid renderer if there is an object and if not NULL checks are unnecessary.
Edit:
Fully implemented BouncingBall::Initialise
void BouncingBall::Initialise(int PositionX,
int PositionY,
int DirectionX,
int DirectionY,
ASCIIRenderer* pRenderer){
m_PositionX = PositionX;
m_PositionY = PositionY;
m_DirectionX = DirectionX;
m_DirectionY = DirectionY;
m_pRenderer = pRenderer;
}
Note the names of the parameters are changed to not match the member variables.
But...
RAII (Resource acquisition is initialization) suggests that you not use a BouncingBall::Initialise
function and instead take advantage of constructors
void BouncingBall::BouncingBall(int PositionX,
int PositionY,
int DirectionX,
int DirectionY,
ASCIIRenderer* pRenderer) : // Member Initializer List
m_pRenderer(pRenderer),
m_PositionX(PositionX),
m_PositionY(PositionY),
m_DirectionX(DirectionX),
m_DirectionY(DirectionY)
{
if (m_pRenderer == NULL)
{
// throw exception here. This will prevent having an improperly
// initialized BouncingBall acting as a ticking timebomb.
// the constructed object will be politely destroyed as if it never existed
}
}
Documentation on Member initializer list.