Sign in to follow this  
spudgun2004

(new) Abstract Class Problem!

Recommended Posts

Hi, I've created a class called Canvas that simply wraps around a DirectDraw surface and does error checking, etc. I also have a Painter16 and Painter32 class that derives from the Canvas class and will do custom 16bit/32bit drawing on the encapsulated surface within the base Canvas class. These two classes, Painter16 and Painter32, are also dervied from a IPainter class that has nothing other than some pure virtual functions and are implemented in the two dervied classes. In my application I have a IPainter* pointer and I check if the display is in 16bit or 32bit mode and create either a Painter16/32 instance and cast it to my IPainter* pointer. Now if I do Painter16* ptr = new Painter16( ... ); IPainter* iptr = ( ( IPainter* )( ptr ) ); delete iptr; it works fine, but doing this IPainter* iptr = new Painter16( ... ) works right up until I do this delete iptr; Does anyone have any ideas why this is happening? Thanks, Michael

Share this post


Link to post
Share on other sites
Hi,

The destructor in the Canvas class is virtual, but the IPainter class does not have anything apart from the the virtual functions.

I also tried a virtual destructor in the IPainter class, but no luck!

Regards,

Michael

Share this post


Link to post
Share on other sites
Quote:
Original post by spudgun2004

Painter16* ptr = new Painter16( ... );
IPainter* iptr = ( ( IPainter* )( ptr ) );
delete iptr;



if Painter16 is a sub-type of IPainter then there is no need to cast from Painter16 to IPainter.

Perhaps you should post your types.

Share this post


Link to post
Share on other sites
you do have to dynamically cast the interface ptr back to the type it was created as.

so Painter16* pPainter = dynamic_Cast<Painter16*>(iPtr);
then

delete pPainter;

that'll do the trick for you!!!
CHeers
Chris

Share this post


Link to post
Share on other sites
Quote:
you do have to dynamically cast the interface ptr back to the type it was created as.


No you don't... You can delete a derived class through a pointer to the base class just fine. Ofcourse, if your destructor is not virtual, the derived class' destructor will never be called.

Now, you never told us what the error was. You just said it 'works fine until'. Is there a compile time error? Does it crash at runtime? What was the error?

[edit: destructor]

[Edited by - Magmai Kai Holmlor on September 2, 2004 11:40:46 PM]

Share this post


Link to post
Share on other sites
Quote:
you can't have a virtual constructor:) Nice try, wise guy:)


I like how you rebutted my typo, but neglected to mention that you were wrong in the first place.

Share this post


Link to post
Share on other sites
I'm not so sure it was a typo and my original post was correct, it would fix the problem:)

Please don't get angry over silly things:) My post was correct and you called it wrong, and I picked apart your post.

Lets call it even!

Cheers
Chris

Share this post


Link to post
Share on other sites
ALL polymorphic classes (classes with virtual functions intended to be used polymorphicaly) should have virtual destructors - and MUST have virtual destructors in order to be used in the way you are using them (in order to delete an object using a base class pointer, the base class must have a virtual destructor).

Remember, that even though your class is abstract, the virtual destructor is NOT abstract, so you must implement it. (It cannot be PURE virtual)


class Base
{
public:
virtual Foo(void) = 0;
virtual Foo2() = 0;

virtual ~Base() {} // notice the implementation
// or you could use this
virtual ~Base();
}

// and implement it in the .cpp file
Base::~Base()
{
}

class Derived : Base
{
public:
// whatever you need here
}


Share this post


Link to post
Share on other sites
Quote:
Original post by spudgun2004
doing this

IPainter* iptr = new Painter16( ... )

works right up until I do this

delete iptr;


Since you're getting an error on a call to delete, there's a good chance that this is a runtime error (since you haven't actually told us this information). If this is the case, throw an assert in before the deletion to verify that you're not trying to delete a pointer to NULL. It's unlikely, but it will at least omit one possibility.

Secondly, when you say that everything works fine up until you try and destroy the object, do you mean that you can perform meaningful operations on the object pointed to by iptr? Can you change the state of the object and obtain the new state information? In other words, is the object *actually* being intialised correctly?

Thirdly, your call to new has an implicit cast from the derived to the base class pointer. This *should* be handled by your compiler, but make sure it is by throwing in a static cast.

Finally, my only other thought is to throw in some output statements into your class destructors to verify what is being called when you try and destruct from a pointer to your virtual base class.

Sorry I can't be of more help.

Timkin

Share this post


Link to post
Share on other sites
Quote:
I'm not so sure it was a typo and my original post was correct, it would fix the problem:)


Sure, it would fix the problem. But it's quite impossible to implement. The whole point of polymorphism is that you don't know the dynamic type of the object, even when it comes time to delete it. How can you cast to the dynamic type if you don't know what it is?

Furthermore, this is -exactly- what the runtime is doing for you already. The runtime looks at the dynamic type information, and calls that destructor first. Then is traces up the inheritance tree, calling each destructor in turn. This is different from normal virtual calls, which don't call the base class functions.

You said, quite clearly, and I will quote so other people might learn from you ignorance, that you must cast to the dynamic type before deleting.
Quote:
you do have to dynamically cast the interface ptr back to the type it was created as.

This is simply wrong. You do NOT have to cast the base pointer to the dynamic type to delete it.

Getting back the OP - spundgun2004, do you have RTTI on? It's only supposed to disable dynamic_cast and type_id (or is it of now?) if it's off, but you never know.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hi,

Sorry I didn't post the error info. I get a run time error on the delete iptr; statement. I don't have the actual details in from of me, but its someting along the lines of "Heap block not invalid..."

After creating the object I can successfully call functions and modify the state of the object with no problems.

I will have to post the class setup later.

Thanks everyone for your help.

Regards,

Michael (spudgun2004)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hi,

This is the kind of message I am getting...

_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

Regards,


Michael (spudgun2004)

Share this post


Link to post
Share on other sites
An assert buried within the runtime. That would suggest several posibilities.

-The class was already deleted.
-It was newed out of a different heap (DLLs?)
-Your pointer is becoming invalid somehow, and doesn't actually point to the object.
-Your pointer points to an object on the stack.

Share this post


Link to post
Share on other sites
Hi,

I've done a small seperate project using the rules suggested by everyone and that worked fine without any problems or assertions I've encountered in my current project.

This means that I am probably doing something wrong somewhere, even though I cannot see any obvious mistakes, so I will go back and re-examine my code.

Thanks everyone for your help. Hope I did not waste you time!

Thanks,


Michael

Share this post


Link to post
Share on other sites
added to Deyja's list of possible causes, if you have mutliple threads accessing the same memory, many subtle issues like this may arise as well ... (if you aren't making threads, you can ignore this).

Share this post


Link to post
Share on other sites
You might have trashed the heap with a buffer overflow. That can overwrite the bread-crumbs the memory debugger leaves around; add that to Xai's list.

Quote:
Original post by chollida
I'm not so sure it was a typo and my original post was correct, it would fix the problem:)

Please don't get angry over silly things:) My post was correct and you called it wrong, and I picked apart your post.

Lets call it even!


dynamic_cast is a code smell, there are certain places they make sense, but deletion is not one of them; we have virtual destructors for this explicit purpose.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this