Jump to content
  • Advertisement
Sign in to follow this  
HeavyStorm

Virtual Destructor and Templates: A Crazy Doubt

This topic is 4482 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

So, there I am, sweating and trembling, looking at my IDE screen trying to understand why a nice delete instruction was crashing my program. It was very dark: I was calling delete upon a pointer to a base interface, hoping that it would destroy the derived class. When that didn't happened and windows informed me that there was an error in MY PROGRAM, I couln't believe it. I started blaming windows, Microsoft and I almost committed the sacrilege of cursing Visual Studio. I expected that, if the correct destructor (the derived class' destructor) wasn't called, at least nothing would be done, since the derived class ( I'll present the classes shortly) had no real data, only two pointers to object. That didn't happen. C++ was trying to do something that he shouldn't, I can't even imagine what. So I inserted a fake destructor in my base class, a virtual one, to make sure the right one was called. That's when things got confused in my mind: my compiler wouldn't let me make a pure virtual destructor, which meant that interfaces don't have destructors. But if that is true, when I kill an interface, why doesn't the right destructor is called? Of course, I have a clue... the derived class is a template, and maybe that is interfering with the dynamic binding. For demonstrative purposes only, here are simulacrums of my classes:
[source=C++]
class Interface
{
   void SomeMethod();
   //virutal ~Interface(){}      // uncomment this!
};

template<class T>
class Implementation : public virtual Interface
{
   typedef (void)(T::*pFun0Void)();
   typedef (void)(T::*pFun1Void)(void*);

    Implementation(T* obj, pFun0Void func)
    {
       object = obj;
       funcPointer = func;
    }

    ~Implementation()
    {
        object = NULL;
        funcPointer = NULL;
    }

   union
   {
      pFun0Void a;
      pFun1Void b;
   } funcPointer;

   T* object;

};

int main()
{
   Interface* test 
        = Implementation<SomeClass>(new SomeClass, SomeClass::someMethod);

   delete test;  // Bug if the virtual destructor in Interface is commented.
   return 0;
}



What makes me crazy, is that, although the solution was obvious, Interfaces shouldn't have destructors, so we can't properly delete a Interface? [Edited by - HeavyStorm on March 16, 2006 1:01:33 PM]

Share this post


Link to post
Share on other sites
Advertisement
I don't understand what your problem is, especially since the code snippet you posted isn't even close to being compileable. If you wish to delete a derived class via a pointer-to-base you must have an accessible virtual destructor in your base class. If you wish to make the destructor pure virtual you must still provide an implementation.

Σnigma

Share this post


Link to post
Share on other sites
If you're going to start talking about compiler errors, please tell us the compiler error so we know what's going on.

The biggest error throughout the code is that all the members are private. (The public inheritance does not make private parent methods public; they're still private.) So I'm not sure how anything here could work.

As a start, try changing Interface to this:


class Interface
{
public:
void SomeMethod();
virutal ~Interface() {}
};



And go from there...

Share this post


Link to post
Share on other sites
Quote:
Original post by HeavyStorm
What makes me crazy, is that, although the solution was obvious, Interfaces shouldn't have destructors, so we can't properly delete a Interface?


In C++, interfaces are just classes. All classes have destructors, although they may have been automatically generated by the compiler instead of by yourself. Further, since C++ requires a virtual destrcutor in order to properly delete a derived class through a pointer-to-base class, all interfaces should have a virtual destructor.

It's quirky enough behavior that it has been at least proposed, if not decided upon, for the next revision of C++ ("C++0x") that if a class contains any virtual functions, that the destuctor will automatically become virtual.

Share this post


Link to post
Share on other sites
Quote:
If you wish to make the destructor pure virtual you must still provide an implementation.

Σnigma


Which means that the destructor would not be pure virtual. Actually, there's no problem, I was just trying to understand why does C++ requires a destructor implementation in a interface if you want a virtual destructor.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Quote:
Original post by HeavyStorm
What makes me crazy, is that, although the solution was obvious, Interfaces shouldn't have destructors, so we can't properly delete a Interface?


In C++, interfaces are just classes. All classes have destructors, although they may have been automatically generated by the compiler instead of by yourself. Further, since C++ requires a virtual destrcutor in order to properly delete a derived class through a pointer-to-base class, all interfaces should have a virtual destructor.

It's quirky enough behavior that it has been at least proposed, if not decided upon, for the next revision of C++ ("C++0x") that if a class contains any virtual functions, that the destuctor will automatically become virtual.


You got what I was saying. I think that what I missed yesterday was the fact that indeed, there are no real interfaces in C++, so that's why I needed the virtual destructor, and of course I had to implement this destructor, because C++ wouldn't let me create a pure virtual destructor. This revision would be good, since if you have anything virtual in a class, you probably expect it to be inherited and so you will need a virtual destructor.

And I'm sorry for the people who took the time to even look at the code... this wasn't my real implementation (it's eight times larger than this), I just wrote this snippet so that you would understand my doubt.

Thanks a lot people, I'm really sorry to bother you all with stuff like this. I was just curious.

Share this post


Link to post
Share on other sites
Quote:
Original post by HeavyStorm
Which means that the destructor would not be pure virtual. Actually, there's no problem, I was just trying to understand why does C++ requires a destructor implementation in a interface if you want a virtual destructor.

Requiring an implementation does not at all change the fact that the destructor is pure virtual. Any pure virtual function can have an implementation. That implementation can only be invoked by an explicit call. The only difference with the destructor is that the explicit call is implicitly included in the derived class destructor.
#include <iostream>

struct Base
{

virtual ~Base() = 0;
virtual void function() = 0;

};

Base::~Base()
{
std::cout << "Base::~Base()\n";
}

void Base::function()
{
std::cout << "Base::function()\n";
}

struct Derived
:
public Base
{

~Derived()
{
std::cout << "Derived::~Derived()\n";
} // implicit call to Base::~Base()

void function()
{
std::cout << "Derived::function()\n";
Base::function();
}

};

int main()
{
Derived d;
d.function();
}

Try running that and then try seperately commenting out the definitions of the two pure virtual functions and noting the compiler/linker errors.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Further, since C++ requires a virtual destrcutor in order to properly delete a derived class through a pointer-to-base class, all interfaces should have a virtual destructor.

It's quirky enough behavior that it has been at least proposed, if not decided upon, for the next revision of C++ ("C++0x") that if a class contains any virtual functions, that the destuctor will automatically become virtual.

That's not true, which is why it isn't standard already. Not all interfaces should have a virtual destructor. The only time a destructor would have to be virtual is if you are to delete children of the type via a pointer to the base. Not all types which have virtual functions are deleted via a pointer to base, which is why you are given the choice.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!