Override Destructor C++

25,895

Solution 1

I may be splitting hairs on the syntax of the words

No, you are definitely not – these are two very different things.

but is it possible to override the destructor?

Yes, and in fact you must do this in many cases. In order for this to work for a polymorphic object, you need to declare the base class destructor as virtual, though:

Parent const& p = Child();

Will properly call p.~Child() at the end of scope because Parent::~Parent is virtual.

Solution 2

Yes, it is possible to override the destructor of a class. In fact, when you define a class hierarchy in which polymorphism is used, you must declare a virtual destructor in the base class.

Overrides of destructors work exactly the same way overrides of normal member functions work in that when you destroy an object by deleteing the object via a pointer to the base class, the destructor of the derived class is properly called. This is why you must have a virtual destructor in the base class for polymorphic hierarchies.

However, there is a difference between virtual destructors and virtual member methods which has nothing to do with the virtual nature of the destructor. That is, when executing code like this:

class A
{
public:  
  virtual void Foo() {}
  virtual ~A() {};
};

class B : public A
{
public:
  void Foo() {};
  ~B() {}
};

int main()
{
  A* a = new B;
  a->Foo();  // B::Foo() is called
  delete a;  // B is destroyed via B::~B()
}

...when you call a->Foo(), the method Foo() in B is called. Since B::Foo() doesn't explicitly call A::Foo(), A::Foo() isn't called.

However, when the object is destroyed via delete a;, first the destructor B::~B() is called, and then after that finishes but before control returns to the program, the base class destructor A::~A() is also called.

Of course this is obvious when you think about it, and again this has nothing to do with the virtual nature of the destructor, but it does behave differently than a normal virtual method call, so I thought I'd point it out.

Obligitory Standard Quotation:

[C++03] 12.4/6 : Destructors

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction (see 12.6).

Solution 3

Yes: you can have virtual destructors, and the only reason is to override them in derived classes.

It looks like this:

class Parent {
public:
    virtual ~Parent();
};

class Child : public Parent {
public:
    virtual ~Child();
};

class Grandchild : public Child {
public:
    ~Grandchild(); // virtual is inherited here
};

Note that the destructor isn't overridden by name like ordinary functions, because the name is always that of the class whose instance you're destroying.

Note also that the parent class' destructors are always called too, so you don't need to duplicate their cleanup code: read up on member object and base-class sub-object construction and destruction order for the details.


Terminology

  • overriding a function means implementing a base-class virtual function in a derived class. You can't change the signature at all (except for using covariant return types). So, an override always has the same signature as an inherited virtual function.
  • overloading a function means implementing multiple functions with the same name (and in some sense the same scope). So, an overload always has a different signature to the others with the same name, doesn't relate directly to virtual dispatch, and isn't necessarily inherited.
Share:
25,895
Danny A
Author by

Danny A

Coder, Overwatcher, reader, cyclist, occasional beer snob.

Updated on September 26, 2020

Comments

  • Danny A
    Danny A over 3 years

    From the C++ FAQ:

    [11.4] Can I overload the destructor for my class? No.

    I realize this means you cannot change the return type, arguments' types nor the number of arguments. I may be splitting hairs on the syntax of the words, but is it possible to override the Parent's destructor?

    class Child : public Parent {
    public:
        virtual Parent::~Parent() {
            // New definition
        }
    };
    

    And for that matter do it recursively?

    class Grandchild : public Child {
    public:
        Child::Parent::~Parent() {
            // An even newer definition
        }
    };
    

    I've read this and a related post and it makes me think because destructors are not inherited, they cannot be overridden, but I've never seen it explicitly stated.

    EDIT: I changed this to reflect the fact that I want to override the Parent's destructor, note Child and Grandchild overriding ~Parent().

    The main reason I am doing this is to maintain Parent's interface while changing the way it is destroyed (the entire reason for the child class). I will have something else managing all Parent's created and will explicitly call their destructors at a later time of my choosing.

    • yngccc
      yngccc almost 11 years
      like you said, destructors are not inherited. when child object destruct, it will call it's own destructor plus its parents destructors. overriding parents destructor in the child class make little sense.
    • Philip Stuyck
      Philip Stuyck almost 11 years
      @yngum of course destructors are inherited. If you don't supply a destructor in the child class overriding the parent, you are in effect inheriting the base class destructor. Overiding destructors of the parent in the derived classes makes a lot of sense like you can see in some of the examples given below.
    • John Dibling
      John Dibling almost 11 years
      @PhilipStuyck: Destructors are not inherited. If you do not declare a destructor, the compiler generates one for you. Base class destructors are called automatically after the implicit destructor executes. See Standard quote in my answer.
    • Pixelchemist
      Pixelchemist almost 11 years
      @PhilipStuyck I don't think this is the case. I suspect the default supplied destructor of a child class to call the base detructor of it's base-sub-object after completion but I think it is not inherited. -edit- See John's answer.
    • John Dibling
      John Dibling almost 11 years
      @PhilipStuyck: Consider, if the destructor of a base class was inherited by a derived class, how would the derived class' members be destroyed?
    • Philip Stuyck
      Philip Stuyck almost 11 years
      by overriding it. Polymorphism is in place for destructors, you can make em virtual hence they are inherited. The only thing that is different from normal inheriting methods is that the parent constructor is called after the child destructor automatically in the reverse order as how the constructors are called, but the constructor itself cannot be virtual.
    • Philip Stuyck
      Philip Stuyck almost 11 years
      If a child class does not have a destructor of its own, the destructor of the parent is going to be called, hence it is inherited. If the child classes has members that need to be cleaned up of course you need to supply a dedicated destructor of the derived class, because the base does not know of those child members. But that does not mean that there is no inheritance in effect.
    • John Dibling
      John Dibling almost 11 years
      @PhilipStuyck: "...hence they are inherited." No, destructors are not inherited. 12.4/3: "If a class has no user-declared destructor, a destructor is declared implicitly."
    • Philip Stuyck
      Philip Stuyck almost 11 years
      @John publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/… shows that you are right John and I was wrong. Of course the way a destructor behaves, going from child to base one by one, makes it look like it is inheriting. The implicitely created destructor is empty, and right after the base class destructor is called.
  • Konrad Rudolph
    Konrad Rudolph almost 11 years
    @yngum Ah. “destructor”, obviously.
  • Philip Stuyck
    Philip Stuyck almost 11 years
    virtual constructors don't exist. And you cannot even call virtual methods in a constructor.
  • Danny A
    Danny A almost 11 years
    @KonradRudolph But does this answer the question? I want Child to redefine that call to ~Parent().
  • yngccc
    yngccc almost 11 years
    @DannyA unfortunately you cannot, there can only be one destructor definition per class.
  • Pete Becker
    Pete Becker almost 11 years
    @PhilipStuyck - you certainly can call virtual functions in a constructor. The call goes to the class currently being constructed, which is not necessarily the most-derived class.
  • Philip Stuyck
    Philip Stuyck almost 11 years
    What I meant is that if you create a base class with a virtual abstract init method, and you call that in the constructor, you will get into serious problems. You can call a virtual method of the base class if it is implemented there and if that is what you want to do. I would be very careful with stuff like that. The point is that classes are only fully constructed once their constructors have finished.
  • Luke Heytens
    Luke Heytens almost 4 years
    The virtual Child destructor is not required because the derived class "inherits" the virtual aspect of the Parent. reference
  • Useless
    Useless almost 4 years
    The keyword "virtual" is not required, true, which is what I wrote the Grandchild class to illustrate. It is still a virtual destructor though, so I'm not sure what you're trying to say.
  • Luke Heytens
    Luke Heytens almost 4 years
    Yeah all I was saying is that the Child class's "virtual" keyword is not required. Both Child and Grandchild are already virtual (like you've illustrated for Grandchild).