Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

mrmrcoleman

Assignment operators with inheritance.

This topic is 5193 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. I have two classes, one derives from the other: class X class Y : public X I need to be able to use assignment operators on class Y. Therefore I have made an overloaded assignment operator in both, and when the Y operator is called it invokes the X operator so that everything is properly copied. However, I now have two Y object but when I try y1 = y2, the assignment operators are not called and usual shallow copying commences which screws everything up? Has anybody come across this before?? In x.h I have class X { public: ... constructors, methods etc X & operator=(X & rhs); } and in the x.cpp I have X & X::operator=(X & rhs) { // code goes here } The same is done for the Y class.. But they just dont get called when I try an assignment?? Thanks for any help guys. Mark Coleman

Share this post


Link to post
Share on other sites
Advertisement
You realize that when you do:

A a = b;

the COPY constructor gets called... versus,

A a;

a = b;

where the assignment operator gets called... So the following are identical:
A a = b;
A a(b);

[edited by - ajas95 on March 5, 2004 3:38:41 AM]

Share this post


Link to post
Share on other sites
My four files.

ScreenEntityBase.h


#include "Globals.h"

class ScreenEntityBase
{
public:
// (De)Constructors

ScreenEntityBase(RECT cScreenRectangle, DWORD cFlags, int cDepthLevel);
ScreenEntityBase(ScreenEntityBase&);
ScreenEntityBase();
virtual ~ScreenEntityBase();

// Over-ridden operators

ScreenEntityBase& ScreenEntityBase::operator=(ScreenEntityBase& rhs);

// Public methods

virtual HRESULT RenderScreenEntity() PURE;
virtual HRESULT HandleMessage(UINT MessageType) PURE;
virtual HRESULT Initialise() PURE;
virtual void OutputInformation() PURE;

DWORD GetFlags();
RECT GetScreenRectangle();
int GetDepthLevel();
DWORD GetScreenEntityID();
bool IsValid();

protected:
DWORD Flags;
RECT ScreenRectangle;
int DepthLevel;
static int IDGenerator;
int ScreenEntityID;
};

#endif


ScreenEntityBase.cpp


#include "ScreenEntityBase.h"

// Constructor

ScreenEntityBase::ScreenEntityBase(RECT cScreenRectangle, DWORD cFlags, int cDepthLevel):
ScreenRectangle(cScreenRectangle),
Flags(cFlags),
DepthLevel(cDepthLevel),
ScreenEntityID(IDGenerator)
{
// Increment the generator

IDGenerator++;
}

// Copy constructor

ScreenEntityBase::ScreenEntityBase(ScreenEntityBase & rhs)
{
// We have to set the flags so that the object is unitialised

// because the DirectX elements will not be present and this could

// lead to run-time errors


Flags = rhs.GetFlags() ^ SCREENENTITY_VALID;
ScreenRectangle = rhs.GetScreenRectangle();
DepthLevel = rhs.GetDepthLevel();
ScreenEntityID = rhs.GetScreenEntityID();
}

// Default constructor

ScreenEntityBase::ScreenEntityBase()
{
// Set the flags so that any user knows this is an uninitialised object at the moment

Flags = 0;
}

// Destructor

ScreenEntityBase::~ScreenEntityBase()
{
// Do nothing here as we have not dynamically assigned any variables

}

// Assignment operator

ScreenEntityBase& ScreenEntityBase::operator=(ScreenEntityBase& rhs)
{
WCHAR test[500];
swprintf(test, L"Flags: %d", Flags);
MessageBox(0, test, L"In base assignment pre assignment", 0);

if(this == &rhs)
return *this;

Flags = rhs.GetFlags() ^ SCREENENTITY_VALID;
ScreenRectangle = rhs.GetScreenRectangle();
DepthLevel = rhs.GetDepthLevel();
ScreenEntityID = rhs.GetScreenEntityID();

swprintf(test, L"Flags: %d", Flags);
MessageBox(0, test, L"In base assignment post assignment", 0);

return *this;
}

DWORD ScreenEntityBase::GetFlags()
{
return Flags;
}

RECT ScreenEntityBase::GetScreenRectangle()
{
return ScreenRectangle;
}

int ScreenEntityBase::GetDepthLevel()
{
return DepthLevel;
}

DWORD ScreenEntityBase::GetScreenEntityID()
{
return ScreenEntityID;
}

bool ScreenEntityBase::IsValid()
{
WCHAR test[500];
swprintf(test, L"Flags: %d", Flags);
MessageBox(0, test, L"Information", 0);

if((Flags & SCREENENTITY_VALID) > 0)
{
return true;
}
else
{
return false;
}
}

int ScreenEntityBase::IDGenerator = 0;


ScreenEntityAnimation.h


#ifndef SCREENENTITYANIMATION_H
#define SCREENENTITYANIMATION_H

#include "ScreenEntityBase.h"
#include "TextureRenderer.h"

class ScreenEntityAnimation : public ScreenEntityBase
{
public:
// (De)Constructors

ScreenEntityAnimation();
ScreenEntityAnimation(ScreenEntityAnimation&);
ScreenEntityAnimation(RECT cScreenRectangle, DWORD cFlags, int cDepthLevel, WCHAR* cAnimationFileLocation);
~ScreenEntityAnimation();

// Over-ridden operators

ScreenEntityAnimation & ScreenEntityAnimation::operator=(ScreenEntityAnimation & rhs);

// Public member functions

HRESULT RenderScreenEntity();
HRESULT HandleMessage(UINT MessageType);
HRESULT Initialise();
WCHAR* GetAnimationFileLocation();
void OutputInformation();

// Sam''s number

// 07903 057906


private:
WCHAR* AnimationFileLocation; // Location of image file on local storage

CComPtr<IGraphBuilder> GraphBuilder; // GraphBuilder

CComPtr<IMediaControl> MediaControl; // Media Control

CComPtr<IMediaPosition> MediaPosition; // Media Position

IMediaEventEx* MediaEvent; // Media Event

TextureRenderer* TextureRendererFilter; // DirectShow Texture renderer

CComPtr<IBaseFilter> Renderer; // Our custom renderer

};

#endif


ScreenEntityAnimation.cpp


#include "ScreenEntityAnimation.h"

// Default constructor

ScreenEntityAnimation::ScreenEntityAnimation()
:ScreenEntityBase()
{
// Do nothing here, the flags reflect the status of the object so that

// it will not be misused

}


// Constructor

ScreenEntityAnimation::ScreenEntityAnimation(RECT cScreenRectangle,
DWORD cFlags,
int cDepthLevel,
WCHAR* cAnimationFileLocation)
:ScreenEntityBase(cScreenRectangle,
cFlags,
cDepthLevel),
AnimationFileLocation(cAnimationFileLocation)
{
// Do nothing here as the object is safe due to the flags being

// set accordingly in the base class constrcutor

}

// copy constructor

ScreenEntityAnimation::ScreenEntityAnimation(ScreenEntityAnimation & rhs)
:ScreenEntityBase(rhs)
{
// Only set the AnimationFileLocation member as the rest need to be reset

// by the object initialisation method which relies upon this field to function


if(rhs.GetAnimationFileLocation())
{
AnimationFileLocation = new WCHAR[(sizeof(rhs.GetAnimationFileLocation())/sizeof(WCHAR)) + 1];
memcpy(AnimationFileLocation, rhs.GetAnimationFileLocation(), sizeof(AnimationFileLocation));
}
else
{
AnimationFileLocation = new WCHAR[1];
*AnimationFileLocation = ''\0'';
}
}

// Destructor

ScreenEntityAnimation::~ScreenEntityAnimation()
{
// Pull graph from Running Object Table (Debug)

RemoveFromROT();

// Shut down the graph

if (!(!MediaControl)) MediaControl->Stop();

if (!(!MediaControl)) MediaControl.Release();
if (!(!MediaEvent)) MediaEvent->Release();
if (!(!MediaPosition)) MediaPosition.Release();
if (!(!Renderer)) Renderer.Release();
if (!(!GraphBuilder)) GraphBuilder.Release();

MessageBox(0, L"", L"", 0);
}

// Assignment operator

ScreenEntityAnimation &ScreenEntityAnimation::operator=(ScreenEntityAnimation &rhs)
{
if(this == &rhs)
return *this;

WCHAR test[500];
swprintf(test, L"
Flags: %d", Flags);
MessageBox(0, test, L"
In base assignment pre assignment", 0);

// Call the base class operator so that the full assignment in carried out

ScreenEntityBase::operator=(rhs);

if(rhs.GetAnimationFileLocation())
{
AnimationFileLocation = new WCHAR[(sizeof(rhs.GetAnimationFileLocation())/sizeof(WCHAR)) + 1];
memcpy(AnimationFileLocation, rhs.GetAnimationFileLocation(), sizeof(AnimationFileLocation));
}
else
{
AnimationFileLocation = new WCHAR[1];
*AnimationFileLocation = ''\0'';
}

swprintf(test, L"
Flags: %d", Flags);
MessageBox(0, test, L"
In base assignment post assignment", 0);

return *this;
}

// RenderScreenEntity - this function renders the image object

// We make the assumption that the direct 3d object has been checked by

// the screen class and therefore does not need to be validated here


HRESULT ScreenEntityAnimation::RenderScreenEntity()
{
if(!(this->IsValid())) // If the graph has not been built yet then do not render

{
MessageBox(0, L"
The entity is not valid", L"Information", 0);
return 0;
}

// The screen object should already have called begin scene and will

// call end scene when all the objects are drawn, therefore these calls

// are not made here. Also we assume that the vertex buffer is valid


// **********************

// Fill the vertex buffer


// Fill the vertex array

TLVERTEX vertices[] =
{
{ (float)ScreenRectangle.left, (float)ScreenRectangle.top, 0.0f, 1.0f, 0.0f, 0.0f }, // x, y, z, rhw, u, v

{ (float)ScreenRectangle.right, (float)ScreenRectangle.top, 0.0f, 1.0f, 1.0f, 0.0f },
{ (float)ScreenRectangle.right, (float)ScreenRectangle.bottom, 0.0f, 1.0f, 1.0f, 1.0f},
{ (float)ScreenRectangle.left, (float)ScreenRectangle.bottom, 0.0f, 1.0f, 0.0f, 1.0f},
};

// Lock the vertex buffer

VOID* pVertices;
if(FAILED(GlobalDirect3D9VertexBuffer->Lock(0,
sizeof(vertices),
(void **)&pVertices,
0)))
{
MessageBox(0, TEXT("
Could not lock Direct3D vertex buffer"), TEXT("Error"), 0);
return false;
}

// Copy across the vertex information

memcpy(pVertices, vertices, sizeof(vertices));

// Unlock the vertex buffer

if(FAILED(GlobalDirect3D9VertexBuffer->Unlock()))
{
MessageBox(0, TEXT("
Could not unlock Direct3D vertex buffer"), TEXT("Error"), 0);
return false;
}

// ***************

// Set the texture

if(TextureRendererFilter->GetAnimationTexture())
{
GlobalDirect3D9Device->SetTexture(0, TextureRendererFilter->GetAnimationTexture());
}
else
{
MessageBox(0, L"
AnimationTexture in accessible", L"", 0);
}

// ***************

// Draw the stream

GlobalDirect3D9Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);

return true;
}

HRESULT ScreenEntityAnimation::HandleMessage(UINT MessageType)
{
// This is like the screen message handling function although the MessageParameter

// is omitted because the correct screen entity should already have been located when

// this function is called


long evCode;
LONG_PTR param1, param2;
HRESULT hr;

// Disregard if we don''t have an IMediaEventEx pointer.

if (MediaEvent == NULL)
{
return false;
}

// Get all the events

while (SUCCEEDED(MediaEvent->GetEvent(&evCode, ¶m1, ¶m2, 0)))
{
MediaEvent->FreeEventParams(evCode, param1, param2);
switch (evCode)
{
case EC_COMPLETE:
if((Flags & ANIMATION_LOOPED) > 0)
{
// The animation needs to be looped so we set it back to the beginning

hr = MediaPosition->put_CurrentPosition(0);
}
else
{
// The animation is not looped so just set the completed to true

Flags = Flags | ANIMATION_FINISHED;
}
break;
}
}
return hr;
}

HRESULT ScreenEntityAnimation::Initialise()
{
// Because both this object and the Direct Show texture renderer need to have

// access to the texture object it is created in the texture renderer object and

// then a pointer can be returned using the GetAnimationTexture()


// Using the private direct show objects the graph is constructed from the file name

// supplied to the constructor


CComPtr<IBaseFilter> pFSrc; // Source Filter

CComPtr<IPin> pFSrcPinOut; // Source Filter Output Pin


// Create the filter graph

if (FAILED(GraphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC)))
{
MessageBox(0, TEXT("
Could not create the filter graph"), TEXT("Error"), 0);
}

// Add the graph to the running object table

AddToROT(GraphBuilder);

HRESULT hr = S_OK;

// Create the Texture Renderer object

TextureRendererFilter = new TextureRenderer(NULL, &hr);
if (FAILED(hr) || !TextureRendererFilter)
{
MessageBox(0, TEXT("
Could not create texturerenderer object"), TEXT("Error"), 0);
}

// Get a pointer to the IBaseFilter on the TextureRenderer, add it to graph

Renderer = TextureRendererFilter;

if (FAILED(GraphBuilder->AddFilter(Renderer, L"
TEXTURERENDERER")))
{
MessageBox(0, TEXT("
Could not add filter to graph"), TEXT("Error"), 0);
}

// Add the source filter to the graph.

hr = GraphBuilder->AddSourceFilter (AnimationFileLocation, L"
SOURCE", &pFSrc);

// If the media file was not found, inform the user.

if(FAILED(hr))
{
MessageBox(0, TEXT("
Could not add source filter to the graph"), TEXT("Error"), 0);
}

if (FAILED(pFSrc->FindPin(L"
Output", &pFSrcPinOut)))
{
MessageBox(0, TEXT("
Could not find output pin"), TEXT("Error"), 0);
}

if (FAILED(GraphBuilder->Render(pFSrcPinOut)))
{
MessageBox(0, TEXT("
Could not render source output pin"), TEXT("Error"), 0);
}

// Get the graph''s media control, event & position interfaces

GraphBuilder.QueryInterface(&MediaControl);
GraphBuilder.QueryInterface(&MediaPosition);
GraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&MediaEvent);

// Add the message notifcation for the graph

MediaEvent->SetNotifyWindow((OAHWND) g_hWnd, WM_GRAPHNOTIFY, ScreenEntityID);

// Start the graph running;

if (FAILED(MediaControl->Run()))
{
MessageBox(0, TEXT("
Could not run the direct show graph"), TEXT("Error"), 0);
}

// Set the valid flag to true so that the object can now be used if it

// was initialised properly

if(!FAILED(hr))
Flags = Flags | SCREENENTITY_VALID;

// Return the status of the intitialisation method

return hr;
}

WCHAR* ScreenEntityAnimation::GetAnimationFileLocation()
{
return AnimationFileLocation;
}

void ScreenEntityAnimation::OutputInformation()
{
// Output the fields that can be output to show what is going on in the object

// This method is used for testing and debugging purposes

WCHAR test[500];
swprintf(test, L"
Flags: %d, RECT Top: %i, RECT Bottom: %i, RECT Left: %i, RECT Right: %i, DepthLevel: %i, ScreenEntityID: %i, File Location: %s",
Flags,
ScreenRectangle.top,
ScreenRectangle.bottom,
ScreenRectangle.left,
ScreenRectangle.right,
DepthLevel,
ScreenEntityID,
AnimationFileLocation);

MessageBox(0, test, L"
Information", 0);
}


Obviously there are more files but these are the core four that seem to be the problem. When I try to assign one ScreenEntityAnimation object to another it ignores the assignment operators and uses a shallow copy as far as I am aware.

Thanks for having a look.

Mark Coleman

Share this post


Link to post
Share on other sites
Apologies for wasting your time...

I have been using pointers to objects, so I was simply copying the pointer all along. I have been awake for 19 hours now!! Mistakes were inevitable

I feel kind of stupid. Anyway thanks for your speedy responses.

Mark Coleman

p.s. If you have any other comments on my code they would be welcome.

Share this post


Link to post
Share on other sites
Your code looks great, except for what the hell is with the indentation on your initializer lists? You using emacs or something?... And lose the PURE macro.

But my only real constructive piece of advice would be to learn to love const-correctness. It's like the most important thing in the world. Seriously. When debugging someone else's code it's really nice to be able to look at a variable's declaration and know whether or not its value will change after construction... or to look at a function and know whether any member of *this will change. If a variable's not const, you KNOW it will change... or if it is const, that's one axis of complexity your brain can remove while code-skimming.

const: Learn it. Use it. Love it.

[edited by - ajas95 on March 5, 2004 4:13:05 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by ajas95
Your code looks great, except for what the hell is with the indentation on your initializer lists? You using emacs or something?...

Hehe. He was clearly using a smaller tab size than the ones these boards use... I use a tabsize of 4 and he may have been too. I always convert to spaces before posting code, for just that reason.

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Upload up to four 1600x1200 screenshots of your projects, registration optional. View all existing ones in the archives..

Share this post


Link to post
Share on other sites
Thanks for the feedback, I have been meaning to get round the whole const tihng for some time, you know any good tuorials?

Also could you tell me why the PURE macro is not a good idea??
I just picked it up somewhere and have been using it ever since! I never really knew how else to do it !?

Mark Coleman

Share this post


Link to post
Share on other sites
Here is one lengthy discussion I found.
And this is a FAQ-based explanation.

They pretty much explain everything, but one thing to keep in mind at all times is that const always modifies the thing to its LEFT. The form where you put it at the beginning is just a special case reknownedly inconsistent. So...

const int i = 5; and
int const i = 5; are identical... a variable i that will never change from 5.

const int *p = &i; is different from
int *const p = &i;

the first case means "p points to an integer that will never change, though p itself might." The second means "I can modify the value at the location that p points to, but p can only ever point to this one thing."

And note that the int *const p = &i; won''t compile if used in conjunction with the const int i = 5; above... why? Because p points to a non-const int, but i is const. You''d have to say instead:

const int *const p = &i; p will only ever point to i and will never change that value.

So you can can see why people get frightened about const... it''s a little hairy at first. And we''re not even talking about overloading based on const-ness yet But it''s one of the most powerful debugging tools you have available, and especially when you start working in teams and have to verify someone else''s code. One thing to realize though is that const will NOT help the compiler optimize your code (though it seems like it should). To understand the problem and become a better human being, you should read about pointer aliasing and the restrict keyword

Good Luck.

Share this post


Link to post
Share on other sites
(sorry off-topic)

void set_opposite( float y[],
const float * a,
int n ) {
for( int i=0; i y = 1.0f - *a;
}

quote:

What happens when set_opposite is called here? The first 50 iterations set a[0]...a[49] to 0.0 The 51st iteration changes a[50] from 1.0 to 0.0. Since *a is aliased to y[50] the subsequent iterations do something different: they set a[51]...[99] to 1.0.


i don''t understand why y[51...99] are set to 1.0?
a break down would be nice, thanks.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!