virtual destructor

Discussion in 'C++' started by Ele, May 22, 2004.

  1. Ele

    Ele Guest

    Is it correct to say that Whenever a class has a virtual member function,
    define its destructor as "virtual"?

    Can a destructor as "pure virtual"? When is it needed to do so?

    For an interface, Interf:

    class Interf
    {
    public:
    virtual void Method() = 0;
    virtual ~Interf();
    };

    class CMyType : public Interf
    {
    public:
    void Method() { }
    ~CMyType() { };
    };

    Should "~Interf()" be declared in "Interf" at all? Should "~Interf()" be
    declared as "virtual" or "pure virtual"?

    Thanks in advance!
     
    Ele, May 22, 2004
    #1
    1. Advertising

  2. Ele

    Jeff Schwab Guest

    Ele wrote:
    > Is it correct to say that Whenever a class has a virtual member function,
    > define its destructor as "virtual"?


    That's a good rule of thumb.

    > Can a destructor as "pure virtual"?


    Yes, but I can't think of a case when it's a good idea.

    > When is it needed to do so?


    I'm not sure it's ever needed. You could use it to prevent a class from
    being instantiated, if you're willing to wait until link time for the
    error message.

    > For an interface, Interf:
    >
    > class Interf
    > {
    > public:
    > virtual void Method() = 0;
    > virtual ~Interf();
    > };
    >
    > class CMyType : public Interf
    > {
    > public:
    > void Method() { }
    > ~CMyType() { };
    > };
    >
    > Should "~Interf()" be declared in "Interf" at all?


    Probably.

    > Should "~Interf()" be
    > declared as "virtual" or "pure virtual"?


    virtual, possibly with an empty definition:

    virtual ~Interf ( ) { }
     
    Jeff Schwab, May 22, 2004
    #2
    1. Advertising

  3. Ele

    JKop Guest

    I've been going over this in my head.


    Let's take a base class, entitled Mammal , and a derived class Dog .


    Mammal's destructor is as so:


    Mammal::~Mammal(void)
    {
    Exhale();
    }


    Now, here's Dog's destructor:

    Dog::~Dog(void)
    {
    Bark();
    }


    So... when a dog dies, it barks, and then exhales.


    Now let's say we have another derived class Poodle .

    class Poodle : public Dog


    And when a poodle dies:

    Poodle::~Poodle(void)
    {
    ForfeitShowMedals();
    }


    So... when a Poodle dies, it forfeits all its show medals, then it barks,
    and then it exhales.



    Long story short, I don't see why there's a need to give Mammal or Dog a
    virtual destructor. Could someone please enlighten me?
     
    JKop, May 22, 2004
    #3
  4. "Ele" <> wrote
    > Is it correct to say that Whenever a class has a
    > virtual member function, define its destructor as
    > "virtual"?


    Unless you have overriding reasons to do so, you should always do that, yes.

    > Can a destructor as "pure virtual"?


    Absolutely.

    > When is it needed to do so?


    When you have a base class that:

    a) is the root of a hierarchy of disparate types
    b) you don't want to make instantiable
    c) has no other virtual functions

    This, of course, is commonly viewed as incredibly bad design, but you still find
    some newcomers who want everything to inherit from a common base class so that
    they can store totally unrelated objects in a container and so they introduce
    cosmic hierarchies.

    > For an interface, Interf:
    >
    > class Interf
    > {
    > public:
    > virtual void Method() = 0;
    > virtual ~Interf();
    > };
    >
    > class CMyType : public Interf
    > {
    > public:
    > void Method() { }
    > ~CMyType() { };
    > };
    >
    > Should "~Interf()" be declared in "Interf" at all?


    Only if you want your code to be correct.

    > Should "~Interf()" be declared as "virtual" or "pure virtual"?


    It doesn't matter either way. Keep in mind, though, that pure virtual destructors
    still need to be implemented since they will be invoked implicitly in the derived
    classes. Some people make destructors pure virual for consistency in classes that
    otherwise have only pure virtual functions. That's purely stylistic and has no
    effect on the code.

    Also, you should get in the habit of specifying 'virtual' in your derived classes
    as well. C++ allows you to omit it, but someone looking at a derived class then
    needs to refer back to the base class to see what's virtual and what isn't. Just
    think of it as an inexpensive but very meaningful comment.

    Claudio Puviani
     
    Claudio Puviani, May 22, 2004
    #4
  5. Ele

    Cy Edmunds Guest

    "Ele" <> wrote in message
    news:02Lrc.46491$...
    > Is it correct to say that Whenever a class has a virtual member function,
    > define its destructor as "virtual"?
    >
    > Can a destructor as "pure virtual"? When is it needed to do so?
    >
    > For an interface, Interf:
    >
    > class Interf
    > {
    > public:
    > virtual void Method() = 0;
    > virtual ~Interf();
    > };
    >
    > class CMyType : public Interf
    > {
    > public:
    > void Method() { }
    > ~CMyType() { };
    > };
    >
    > Should "~Interf()" be declared in "Interf" at all? Should "~Interf()" be
    > declared as "virtual" or "pure virtual"?
    >
    > Thanks in advance!
    >



    http://www.gotw.ca/gotw/031.htm

    My own style is to never use a pure virtual destructor. I think a good base
    class for a polymorphic hierarchy should be written as follows:

    class SomeName
    {
    public:
    virtual void some_func() = 0;
    // other functions as required
    virtual ~SomeName() {}
    };

    1) no data
    1.1) no constructor
    1.2) no private section
    2) all functions pure virtual (at least one defined)
    3) a do-nothing virtual destructor

    --
    Cycho{HHR}
    http://home.rochester.rr.com/cyhome/
     
    Cy Edmunds, May 22, 2004
    #5
  6. Ele

    David Harmon Guest

    On Sat, 22 May 2004 12:29:57 -0400 in comp.lang.c++, Jeff Schwab
    <> wrote,
    >> Can a destructor as "pure virtual"?

    >
    >Yes, but I can't think of a case when it's a good idea.


    A pure virtual destructor is sometimes used to make an abstract class,
    when there are no other virtual functions in that base class than make
    sense to be pure. You also still provide the destructor implementation
    in that case.

    Or, so says the theory. It's rare.
     
    David Harmon, May 22, 2004
    #6
  7. JKop wrote:
    > Long story short, I don't see why there's a need to give Mammal or Dog a
    > virtual destructor. Could someone please enlighten me?


    Sure.. because if you don't, and a derived object is destroyed (in the
    context of a base object), then your destructor will NOT get called!

    For example:

    #include <cstdio>

    class Base
    {
    public:

    Base()
    {
    printf("Base::Base()\n");
    }

    ~Base() // this SHOULD be virtual!
    {
    printf("Base::~Base()\n");
    }
    };

    class Derived: public Base
    {
    public:

    Derived()
    {
    printf("Derived::Derived()\n");
    }

    ~Derived() // implicitly virtual if Base::~Base is virtual
    {
    printf("Derived::~Derived()\n");
    }
    };


    void PerformeDelete(Base* b)
    {
    delete b;
    }


    int main()
    {
    Base* b = new Base;
    Derived* d = new Derived;

    printf("deleting b\n");
    PerformeDelete(b);

    printf("deleting d\n");
    PerformeDelete(d);
    }


    --Steve
     
    Stephen Waits, May 22, 2004
    #7
  8. Ele

    Duane Hebert Guest

    "JKop" <> wrote in message news:9HNrc.124$...
    >
    > Long story short, I don't see why there's a need to give Mammal or Dog a
    > virtual destructor. Could someone please enlighten me?


    Mammal *Animal = new Dog();
    delete Animal;

    If the dtor in mammal is not virtual,
    will it bark?

    When you create a class instance polymorphically via a base
    class pointer, the dtor must be virtual to ensure that the correct
    dtors get called.
     
    Duane Hebert, May 22, 2004
    #8
  9. Jeff Schwab wrote:
    >
    > David Harmon wrote:
    > > On Sat, 22 May 2004 12:29:57 -0400 in comp.lang.c++, Jeff Schwab
    > > <> wrote,
    > >
    > >>>Can a destructor as "pure virtual"?
    > >>
    > >>Yes, but I can't think of a case when it's a good idea.

    > >
    > >
    > > A pure virtual destructor is sometimes used to make an abstract class,
    > > when there are no other virtual functions in that base class than make
    > > sense to be pure. You also still provide the destructor implementation
    > > in that case.

    >
    > If you provide an implementation for the destructor, in what way is the
    > destructor "pure virtual?" If the destructor of the base class is pure
    > virtual, how do you instantiate the derived classes? Shouldn't this
    > code fail to link properly?
    >
    > struct Base { virtual ~Base ( ) = 0; };
    > struct Derived: Base { ~Derived ( ) { } };
    >
    > int main ( ) { Derived d; }


    10.3.8 says:
    "A virtual function [...] shall be defined, or declared pure [...] or both;
    [...]"

    So yes, you can provide a definition for a pure virtual function. Such
    function still makes its class abstract (no objects of /that/ class can be
    created). However, you can call a (defined) pure virtual function on an
    object of a concrete derived class using a qualified name.
    In the case of a virtual destructor (pure or not), a definition must be
    provided if the class at hand or any of its derived classes are to be
    instantiated.

    As a practical implication, the following two definitions are not equivalent:

    //abstract
    ///////////////////////////////////
    class A {
    public:
    virtual ~A() = 0;
    };
    A::~A() {}

    //can be instantiated
    ///////////////////////////////////
    class A {
    public:
    virtual ~A() {}
    };


    Denis
     
    Denis Remezov, May 23, 2004
    #9
  10. Ele

    JKop Guest

    Thanks Stephen Waits and Duane Hebert for your replies, although I found the
    both of them to be HEAVILY contrived.


    Why would one function delete memory allocated by another?


    And why would you do the following:


    Mammal restt = new Dog;

    delete restt;



    Looks like child's play to me.

    That said, the overhead of declaring the destructor virtual is minimal by
    today's standards, so maybe your point is stronger than mine.


    -JKop
     
    JKop, May 23, 2004
    #10
  11. Ele

    JKop Guest

    JKop posted:

    > Mammal restt = new Dog;



    TYPO TYPO TYPO


    Mammal* restt = new Dog;


    -JKop
     
    JKop, May 23, 2004
    #11
  12. Ele

    Jorge Rivera Guest

    > A pure virtual destructor is sometimes used to make an abstract class,
    > when there are no other virtual functions in that base class than make
    > sense to be pure. You also still provide the destructor implementation
    > in that case.
    >


    I have tried not providing an implementation to the destructor, and I
    always get link errors.

    Ex:

    class PureVirtual
    {
    public:
    virtual ~PureVirtual()=0;
    virtual implementMe()=0;
    };

    class Derived : public PureVirtual
    {
    public:
    ~Derived(){}
    virtual implementMe(){}
    };

    int main()
    {
    Derived a;
    return 0;
    }


    This will start whining about PureVirtual::~PureVirtual() not found...
     
    Jorge Rivera, May 23, 2004
    #12
  13. Ele

    Jeff Schwab Guest

    JKop wrote:
    > Thanks Stephen Waits and Duane Hebert for your replies, although I found the
    > both of them to be HEAVILY contrived.
    >
    >
    > Why would one function delete memory allocated by another?


    For a number of very good reasons. For example, memory is allocated in
    an object's constructor, then deleted in the object's destructor.

    > And why would you do the following:
    >
    >
    > Mammal restt = new Dog;
    >
    > delete restt;


    You wouldn't. However, you might do something like this:

    std::vector< Animal* > animals;

    // Populate the vector according to factors
    // available only at run-time.

    // Call on each animal to do something (e.g.
    // make noise), and rely on polymorphism to
    // make sure the dogs bark, while the cats
    // meow.

    // Delete each animal in the vector through
    // the pointer-to-base.

    > Looks like child's play to me.


    :)

    > That said, the overhead of declaring the destructor virtual is minimal by
    > today's standards, so maybe your point is stronger than mine.


    Are you sure about that? Not all code is meant for desktop machines
    with plentiful RAM. Anyway, I find the "hardware is cheap, so let's
    waste it" philosophy distasteful at best.
     
    Jeff Schwab, May 23, 2004
    #13
  14. Ele

    Jeff Schwab Guest

    David Harmon wrote:
    > On Sat, 22 May 2004 12:29:57 -0400 in comp.lang.c++, Jeff Schwab
    > <> wrote,
    >
    >>>Can a destructor as "pure virtual"?

    >>
    >>Yes, but I can't think of a case when it's a good idea.

    >
    >
    > A pure virtual destructor is sometimes used to make an abstract class,
    > when there are no other virtual functions in that base class than make
    > sense to be pure. You also still provide the destructor implementation
    > in that case.


    If you provide an implementation for the destructor, in what way is the
    destructor "pure virtual?" If the destructor of the base class is pure
    virtual, how do you instantiate the derived classes? Shouldn't this
    code fail to link properly?

    struct Base { virtual ~Base ( ) = 0; };
    struct Derived: Base { ~Derived ( ) { } };

    int main ( ) { Derived d; }
     
    Jeff Schwab, May 23, 2004
    #14
  15. Ele

    Jeff Schwab Guest

    Denis Remezov wrote:

    > 10.3.8 says:
    > "A virtual function [...] shall be defined, or declared pure [...] or both;
    > [...]"
    >
    > So yes, you can provide a definition for a pure virtual function.


    Thanks, Denis. I've never seen a pure virtual function with a
    definition before now. Live and learn!
     
    Jeff Schwab, May 23, 2004
    #15
  16. JKop wrote:
    > Thanks Stephen Waits and Duane Hebert for your replies, although I found the
    > both of them to be HEAVILY contrived.
    >
    > Why would one function delete memory allocated by another?


    MyContainer< Base > blah;

    blah.push_back( new Derived );

    Now stop fighting it and embrace it.. it is how it is.

    --Steve
     
    Stephen Waits, May 24, 2004
    #16
  17. Ele

    Luther Baker Guest

    Stephen Waits wrote:
    > JKop wrote:
    >
    >> Thanks Stephen Waits and Duane Hebert for your replies, although I
    >> found the both of them to be HEAVILY contrived.
    >>
    >> Why would one function delete memory allocated by another?

    >
    >
    > MyContainer< Base > blah;
    >
    > blah.push_back( new Derived );
    >
    > Now stop fighting it and embrace it.. it is how it is.



    Fix the typo

    <Base*>

    and beware, your example is leaking memory.

    Hth,

    -Luther
     
    Luther Baker, May 24, 2004
    #17
  18. Ele

    Old Wolf Guest

    JKop <> wrote:
    > And why would you do the following:
    >
    > Mammal restt = new Dog;
    > delete restt;
    >
    > Looks like child's play to me.


    Looks like polymorphism to me (go look it up in your C++ books).
    The idea is that you could write a function, eg. "greet",
    and call it:
    restt->greet();
    that works for any Mammal, but calls different code for different
    mammals. (eg. Dog::greet() { bark(); } and Fish::greet() { swim(); }
    This sort of thing happens a lot in real world programming. We'd
    appreciate it if you stop your habit of dismissing things that you
    don't see a use for.
     
    Old Wolf, May 24, 2004
    #18
  19. Ele

    Luther Baker Guest

    JKop wrote:
    >
    > And why would you do the following:
    >
    >
    > Mammal restt = new Dog;
    >
    > delete restt;
    >


    I'm not sure I understand your question - so I apologize if I'm off
    base, but ... programming to interfaces is a fundamental principal of OO
    design. One way to do this is to use base class pointers to concrete
    derived class implementations.

    To get a base class pointer to call a derived class method, the method
    must be declared virtual. Lets look at a base class Theme:

    Theme* theme = ThemeFactory.getUserTheme();

    In this case, the factory will return a concrete instance of a class
    derived from theme. Any call to a virtual method made by *theme* will
    call the derived class' method. Any call to a non-virtual method made by
    *theme* will enact its own implementation of said method.

    Now, if the Derived Class constructor creates resources. For example,
    the AMEX theme creates a pool of database connections to the Dow Jones
    interface portal available on the local network. So, unbeknownst to the
    base class, the derived class has allocated resources.

    The resources could be heap memory for char*s or it might be something
    more elaborate. Whatever the case - when the base class pointer is
    eventually deleted, how are the resources the derived class acquired
    going to be released?

    If the base class destructor is NOT virtual, then the derived class will
    never be told that the base class pointer has been deleted. If the
    destructor IS virtual, then the derived class destructor will be called.

    Some smaller projects may in fact get by without using virtual
    destructors, but in most large projects - it would be the norm that
    classes should indeed have virtual destructors.

    For a better example and discussion on the topic, see Exceptional C++,
    Herb Sutter, pg 75, and work through item 21. Specifically, take a look
    at the guideline on page 77.

    -Luther
     
    Luther Baker, May 24, 2004
    #19
  20. Ele

    JKop Guest

    Here's what I'm getting at:


    Why would you cast a Dog* to a Mammal*? as in:


    Mammal restt = new Dog;
    delete restt;


    as opposed to:


    Dog restt = new Dog;
    delete restt;



    Anyway, I see what yous are getting at, end of discussion.


    For the next version of C++ I suggest:

    class Mammal
    {
    virtual_ifderived ~Mammal(void);
    };



    -JKop
     
    JKop, May 24, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Calvin Lai
    Replies:
    7
    Views:
    563
    Calvin Lai
    Dec 18, 2003
  2. Chunhui Han
    Replies:
    2
    Views:
    512
  3. frs
    Replies:
    20
    Views:
    773
    Alf P. Steinbach
    Sep 21, 2005
  4. arun
    Replies:
    2
    Views:
    553
    benben
    Jun 13, 2006
  5. Jimmy Hartzell
    Replies:
    0
    Views:
    426
    Jimmy Hartzell
    May 19, 2008
Loading...

Share This Page