virtual destructor

E

Ele

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

Jeff Schwab

Ele said:
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 ( ) { }
 
J

JKop

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?
 
C

Claudio Puviani

Ele said:
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
 
C

Cy Edmunds

Ele said:
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
 
D

David Harmon

On Sat, 22 May 2004 12:29:57 -0400 in comp.lang.c++, Jeff Schwab
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.
 
S

Stephen Waits

JKop said:
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
 
D

Duane Hebert

JKop said:
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.
 
D

Denis Remezov

Jeff said:
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
 
J

JKop

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
 
J

Jorge Rivera

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...
 
J

Jeff Schwab

JKop said:
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.
 
J

Jeff Schwab

David said:
On Sat, 22 May 2004 12:29:57 -0400 in comp.lang.c++, Jeff Schwab



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; }
 
J

Jeff Schwab

Denis said:
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!
 
S

Stephen Waits

JKop said:
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
 
L

Luther Baker

Stephen said:
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
 
O

Old Wolf

JKop said:
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.
 
L

Luther Baker

JKop said:
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
 
J

JKop

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top