Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

virtual fn, destructor

1 view
Skip to first unread message

DavidW

unread,
Dec 11, 2008, 6:42:05 PM12/11/08
to
Hello,

I just to confirm a rule.

class B
{
public:
virtual ~B() {}
virtual void f();
};

class D : public B
{
public:
void f();
};

The virtual ~B() is necessary because B has at least one virtual function, but
an explicit d'tor is not required in derived classes. Correct?


joe...@gmail.com

unread,
Dec 11, 2008, 7:05:15 PM12/11/08
to

Yes. You are correct. You will have a lot of people respond with a
lot of detail about when you really need, and when you really don't
need a virtual destructor, but "virtual destructor required when there
are any virtual functions" is a good simple rule to live by.

Joe C

Triple-DES

unread,
Dec 11, 2008, 7:13:04 PM12/11/08
to
On 12 Des, 00:42, "DavidW" <n...@email.provided> wrote:
> Hello,
>
> I just to confirm a rule.
>
> class B
> {
> public:
>     virtual ~B() {}
>     virtual void f();
>
> };
>
> class D : public B
> {
> public:
>     void f();
>
> };
>
> The virtual ~B() is necessary because B has at least one virtual function,

If you are going to delete D objects through a pointer to B, then the
virtual destructor is necessary, even if there are no other virtual
functions.

> but an explicit d'tor is not required in derived classes. Correct?

Correct.

DavidW

unread,
Dec 11, 2008, 7:30:50 PM12/11/08
to
Triple-DES wrote:
> On 12 Des, 00:42, "DavidW" <n...@email.provided> wrote:
>> Hello,
>>
>> I just to confirm a rule.
>>
>> class B
>> {
>> public:
>> virtual ~B() {}
>> virtual void f();
>>
>> };
>>
>> class D : public B
>> {
>> public:
>> void f();
>>
>> };
>>
>> The virtual ~B() is necessary because B has at least one virtual
>> function,
>
> If you are going to delete D objects through a pointer to B, then the
> virtual destructor is necessary, even if there are no other virtual
> functions.

Right, but my question is more about the standard. I thought that it actually
demanded the virtual destructor in B, whether you delete a D via a B* or not.


DavidW

unread,
Dec 11, 2008, 7:31:06 PM12/11/08
to

Okay, thanks.


joe...@gmail.com

unread,
Dec 11, 2008, 8:15:25 PM12/11/08
to

No, it does not require it.
Joe Cook

Triple-DES

unread,
Dec 11, 2008, 9:10:51 PM12/11/08
to
On 12 Des, 01:30, "DavidW" <n...@email.provided> wrote:
> Triple-DES wrote:
> > If you are going to delete D objects through a pointer to B, then the
> > virtual destructor is necessary, even if there are no other virtual
> > functions.
>
> Right, but my question is more about the standard. I thought that it actually
> demanded the virtual destructor in B, whether you delete a D via a B* or not.

It does not, as Joe pointed out. That would make standard classes like
std::less ill-formed, since they inherit from std::binary_function
(which has a public non-virtual dtor).

The virtual dtor requirement is given in 5.3.5/3:
In the first alternative (delete object ), if the static type of the
operand is different from its dynamic type, the static type shall be a
base class of the operand’s dynamic type and the static type shall
have a virtual destructor or the behavior is undefined.

DavidW

unread,
Dec 11, 2008, 9:37:25 PM12/11/08
to
Triple-DES wrote:
> On 12 Des, 01:30, "DavidW" <n...@email.provided> wrote:
>> Triple-DES wrote:
>>> If you are going to delete D objects through a pointer to B, then
>>> the virtual destructor is necessary, even if there are no other
>>> virtual functions.
>>
>> Right, but my question is more about the standard. I thought that it
>> actually demanded the virtual destructor in B, whether you delete a
>> D via a B* or not.
>
> It does not, as Joe pointed out. That would make standard classes like
> std::less ill-formed, since they inherit from std::binary_function
> (which has a public non-virtual dtor).

The std::less and std::binary_function in one compiler I looked at don't contain
any virtual functions, though.

> The virtual dtor requirement is given in 5.3.5/3:
> In the first alternative (delete object ), if the static type of the
> operand is different from its dynamic type, the static type shall be a
> base class of the operand’s dynamic type and the static type shall
> have a virtual destructor or the behavior is undefined.

That must be what I was confusing it with. I knew there was a case where no
virtual d'tor was non-conforming. Thanks.


Triple-DES

unread,
Dec 11, 2008, 10:23:40 PM12/11/08
to
On 12 Des, 03:37, "DavidW" <n...@email.provided> wrote:
> Triple-DES wrote:
> > On 12 Des, 01:30, "DavidW" <n...@email.provided> wrote:
> >> Triple-DES wrote:
> >>> If you are going to delete D objects through a pointer to B, then
> >>> the virtual destructor is necessary, even if there are no other
> >>> virtual functions.
>
> >> Right, but my question is more about the standard. I thought that it
> >> actually demanded the virtual destructor in B, whether you delete a
> >> D via a B* or not.
>
> > It does not, as Joe pointed out. That would make standard classes like
> > std::less ill-formed, since they inherit from std::binary_function
> > (which has a public non-virtual dtor).
>
> The std::less and std::binary_function in one compiler I looked at don't contain
> any virtual functions, though.

Right, you were talking about whether it was required for base classes
_with virtual functions_. I just wanted to give an example of a base
class with a non-virtual dtor.

SG

unread,
Dec 12, 2008, 3:40:23 AM12/12/08
to
On 12 Dez., 00:42, "DavidW" <n...@email.provided> wrote:
> I just to confirm a rule.
>
> class B
> {
> public:
>     virtual ~B() {}
>     virtual void f();
>
> };
>
> class D : public B
> {
> public:
>     void f();
>
> };
>
> The virtual ~B() is necessary because B has at least one virtual function

It's only necessary if you intend to delete an object of a derived
type through a pointer to the base class. If you DON'T need this you
can make the dtor PROTECTED and non-virtual in the base class.

Cheers!
SG

James Kanze

unread,
Dec 12, 2008, 4:41:12 AM12/12/08
to

Actually, the usual rule is that the base class destructor must
be either virtual or protected. And of course, it is a
"programming standards" rule, not something imposed by the
standard.

The standard actually violates it in several cases. Arguably,
it shouldn't, and the classes in question should have empty
protected destructors. Except that that would impose
restrictions on classes deriving from them, since no class
deriving from them would have a trivial destructor.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Martin Drautzburg

unread,
Dec 13, 2008, 3:01:35 AM12/13/08
to
SG wrote:

> It's only necessary if you intend to delete an object of a derived
> type through a pointer to the base class. If you DON'T need this you
> can make the dtor PROTECTED and non-virtual in the base class.

Sorry if this is a silly question, but can't I simply make *all*
destuctors virtual as a rule? What would I lose?

Bill

unread,
Dec 13, 2008, 4:23:04 AM12/13/08
to

"Martin Drautzburg" <Martin.D...@web.de> wrote in message
news:2932209.Y...@beaureve.gmx.net...

Probably a bit of performance due to unnecessary calls to the destructors
you define (in those cases where such a call is unnecesary). Your ideas also
increases the complexity of your code (suggesting the of the use of
inheritance even when this may not be the case). I'm not exactly an expert,
but those are my first thoughts concerning your idea.

Bill


James Kanze

unread,
Dec 13, 2008, 4:56:06 AM12/13/08
to
On Dec 13, 9:01 am, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:

Static initialization. Agglomerate initialization. C
compatible layout. Also a bit of memory, which could be an
issue in value type objects kept in arrays. (In my work, the
first three are the most frequent considerations, but I'm sure
that there are cases where the fourth is important as well.)

More generally, the question is what do you gain by making all
destructors virtual?

peter koch

unread,
Dec 13, 2008, 5:48:19 AM12/13/08
to

I believe that it is a good rule to have a virtual destructor in all
base-classes that have any virtual function. You can then remove the
virtual destructor in the cases where it does not matter and
performance tells you not to.

In cases where no virtual functions are defined, it would be silly to
introduce a virtual destructor "just in case".

/Peter

Bill

unread,
Dec 13, 2008, 2:57:09 PM12/13/08
to

"James Kanze" <james...@gmail.com> wrote in message
news:9cf19684-00a0-4a90...@35g2000pry.googlegroups.com...

On Dec 13, 9:01 am, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:
> SG wrote:
> > It's only necessary if you intend to delete an object of a
> > derived type through a pointer to the base class. If you
> > DON'T need this you can make the dtor PROTECTED and
> > non-virtual in the base class.

> Sorry if this is a silly question, but can't I simply make
> *all* destuctors virtual as a rule? What would I lose?

Static initialization.

Are you referring here to function calls prescribed during compilation, or
something else?
Bill


Martin Drautzburg

unread,
Dec 13, 2008, 2:52:49 PM12/13/08
to
James Kanze wrote:

> On Dec 13, 9:01 am, Martin Drautzburg <Martin.Drautzb...@web.de>

>> Sorry if this is a silly question, but can't I simply make


>> *all* destuctors virtual as a rule? What would I lose?
>
> Static initialization. Agglomerate initialization. C
> compatible layout.

Wow

> More generally, the question is what do you gain by making all
> destructors virtual?

Well I would not have to worry about them anymore.

Actually whenever I do some C++ coding (which is admittedly a rare
event) I stumble across this "virtual" thingy. In my coding
style "virtual" is the *most* *natural* thing.

I make lots and lots of mistakes because I forget to put "virtual" here
and "virtual" there. When I hold an object in my hand and I want to
invoke a method of this object it hardly crosses my mind that I might
not invoke a method of *this* object but a method which is selected by
the type of variable holding the object. Headaches.

So I keep thinking: why not just make *every* function and *every*
destructor virtual (and rename "virtual" to "natural"), if that
relieves the headaches.

I wonder what is the reason for this "virtual" complexity. Could be C
compatibility. It is certainly not multiple inheritence because other
multiple-inheritance languages can live without "virtual". Also static
typing is unlikely to be the cause (for the same reason).

James Kanze

unread,
Dec 13, 2008, 3:50:41 PM12/13/08
to
On Dec 13, 8:57 pm, "Bill" <Bill_NOS...@comcast.net> wrote:
> "James Kanze" <james.ka...@gmail.com> wrote in message

> Static initialization.

No. I'm referring to the initialization which is required to
take place before dynamic initialization. Things like:

struct A { int b ; int c ; } ;
A a = { 1, 2 } ;

That's static initialization. It occurs before anything you
wrote will occur. And it can only occur if the constructor is
trivial. Which it isn't if the class has any virtual functions.

James Kanze

unread,
Dec 13, 2008, 3:57:14 PM12/13/08
to
On Dec 13, 8:52 pm, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:

> James Kanze wrote:
> > More generally, the question is what do you gain by making
> > all destructors virtual?

> Well I would not have to worry about them anymore.

Yes and no. You still have to consider what they should contain
(supposing that they should contain something). And you still
have to decide whether the class should support derivation or
not. (Most classes don't, or shouldn't.)

> Actually whenever I do some C++ coding (which is admittedly a
> rare event) I stumble across this "virtual" thingy. In my
> coding style "virtual" is the *most* *natural* thing.

That's somewhat surprising. In my code, it depends very much on
what the class is doing, and unless there is an inversion of
control, it's very rare that there be any virtual public
functions. From experience, over half of my classes are value
types, and don't support derivation at all.

Note that this was also true in Java---over half of my classes
in Java were final, because inheriting from them would have been
a mistake. And instead of "interfaces", I mainly used abstract
classes, with the public functions declared final. Of course,
I'm also a great fan of programming by contract---in my
experience, it leads to much more robust and maintainable code.

> I make lots and lots of mistakes because I forget to put
> "virtual" here and "virtual" there. When I hold an object in
> my hand and I want to invoke a method of this object it hardly
> crosses my mind that I might not invoke a method of *this*
> object but a method which is selected by the type of variable
> holding the object. Headaches.

> So I keep thinking: why not just make *every* function and
> *every* destructor virtual (and rename "virtual" to
> "natural"), if that relieves the headaches.

> I wonder what is the reason for this "virtual" complexity.
> Could be C compatibility. It is certainly not multiple
> inheritence because other multiple-inheritance languages can
> live without "virtual". Also static typing is unlikely to be
> the cause (for the same reason).

It's probably mainly just good sense, and good software
engineering. Most functions shouldn't be virtual. When you
declare a function virtual, you've opened a hole with regards to
your class invariants, and increased the chances for error. So
you don't do it unless it serves a purpose, and usually, you
don't do it for public functions, which can be called by anyone.

James Kanze

unread,
Dec 13, 2008, 4:00:15 PM12/13/08
to
On Dec 13, 11:48 am, peter koch <peter.koch.lar...@gmail.com> wrote:
> On 13 Dec., 09:01, Martin Drautzburg <Martin.Drautzb...@web.de> wrote:

> > SG wrote:
> > > It's only necessary if you intend to delete an object of a
> > > derived type through a pointer to the base class. If you
> > > DON'T need this you can make the dtor PROTECTED and
> > > non-virtual in the base class.

> > Sorry if this is a silly question, but can't I simply make
> > *all* destuctors virtual as a rule? What would I lose?

> I believe that it is a good rule to have a virtual destructor
> in all base-classes that have any virtual function. You can
> then remove the virtual destructor in the cases where it does
> not matter and performance tells you not to.

Presumably, if a class has virtual functions, it is designed for
inheritance. So either the destructor should be virtual, or it
should not be public. (I've encountered more than one case
where it was necessary to impose pre-conditions on delete. To
do this, you declare the destructor protected, and require
client code to call a member function---possibly static, but not
necessarily so---which verifies the pre-conditions before
calling delete.)

> In cases where no virtual functions are defined, it would be
> silly to introduce a virtual destructor "just in case".

Certainly.

Martin Drautzburg

unread,
Dec 13, 2008, 7:35:56 PM12/13/08
to
James Kanze wrote:
> When you
> declare a function virtual, you've opened a hole with regards to
> your class invariants, and increased the chances for error.

Wow, that's an interesting point (and well phrased). I'll have to think
about that.

> So
> you don't do it unless it serves a purpose, and usually, you
> don't do it for public functions, which can be called by anyone.

Okay, I understand we have two different philosophies here. What I
question in your philosophy is that you assume that the author of a
class can forsee it's future use. That's kind of a pessimistic way of
seeing things. It focusses on preventing programmers from making
mistakes, rather than enabling them to do things *right*.

Declaring classes final always seemed kind of rude to me. Who am I to
decide that nobody will come up with a good idea for subclassing my
class. This person could even be me, one year in the future. You need
some enomous foresight to decide that correctly. And if your class
shouldn't be subclassed for really obvious reasons, then that thing
shouldn't be a class in the first place.

But I understand you "contract" approach. Not limiting a class'es usage
by declaring everything public and virtual isn't much of a conract. You
want statements like "do not use indoors" attached to a class, where
I'd say: "let them use it indoors, if they know what they're doing".

Cheers
Martin

zr

unread,
Dec 14, 2008, 7:31:36 AM12/14/08
to

I may have either misunderstood you or do not understand how STL
containers work, but don't STL containers call their stored objects`
destructors? Doesn't this require the destructors to be public?

Juha Nieminen

unread,
Dec 14, 2008, 8:40:01 AM12/14/08
to
Martin Drautzburg wrote:
> Actually whenever I do some C++ coding (which is admittedly a rare
> event) I stumble across this "virtual" thingy. In my coding
> style "virtual" is the *most* *natural* thing.

You have to be aware of the price you pay by using virtual functions.

Practically with all C++ compilers (I'm not aware of any compiler
which would do this differently) if your class has any virtual functions
(such as a virtual destructor), the size of the class increases by the
size of one pointer.

This may be completely irrelevant with large classes or classes which
are instantiated only a few times. However, if you have a class which is
very small (eg. it only has one or two ints as members, or such), and
you instantiate this class millions of times (eg. into a std::vector or
whatever), the memory consumption can grow significantly. (For instance,
if your class is composed eg. of one int, and you make eg. the
destructor virtual, the memory consumption of the instances of the class
will double).

Practical example: Suppose you have a class named "Pixel", which
contains four unsigned char members: red, green, blue and alpha. As it
is, one instantiation of this class will require 4 bytes of memory. If
you, for example, represent an image as a std::vector<Pixel>, the memory
consumption will be the amount of pixels times 4 bytes.

However, if you go and needlessly make the destructor of "Pixel"
virtual, the memory consumption will double (or triple if you are
compiling to a 64-bit system, where pointers are 8 bytes large).

It is quite unlikely that you will ever inherit anything from "Pixel"
(especially if your basic datatype is std::vector<Pixel>, which does not
in itself support specialization of the elements), so making any
function virtual would only be a waste of memory.

Another price to pay is that calling a virtual function is slightly
slower than calling a non-virtual one. This might not be relevant in
most cases, but with small functions which get called millions of times
per second, it might make a difference.

> So I keep thinking: why not just make *every* function and *every*
> destructor virtual (and rename "virtual" to "natural"), if that
> relieves the headaches.

Because it causes overhead, especially with very small classes.

> I wonder what is the reason for this "virtual" complexity.

Because the design principle of the C++ language is "you don't pay for
what you don't use".

Pete Becker

unread,
Dec 14, 2008, 10:35:03 AM12/14/08
to
On 2008-12-13 19:35:56 -0500, Martin Drautzburg
<Martin.D...@web.de> said:

> James Kanze wrote:
>> When you
>> declare a function virtual, you've opened a hole with regards to
>> your class invariants, and increased the chances for error.
>
> Wow, that's an interesting point (and well phrased). I'll have to think
> about that.
>
>> So
>> you don't do it unless it serves a purpose, and usually, you
>> don't do it for public functions, which can be called by anyone.
>
> Okay, I understand we have two different philosophies here. What I
> question in your philosophy is that you assume that the author of a
> class can forsee it's future use.

Well, yes: that's called design. When you design a class you decide
what you intend it to be used for and you do what you can to ensure
that it will do what you've decided it should do. If you put in hooks
"just in case", then you're not designing.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

SG

unread,
Dec 14, 2008, 12:03:34 PM12/14/08
to
On 14 Dez., 13:31, zr <zvir...@gmail.com> wrote:
> On Dec 12, 11:41 am, James Kanze <james.ka...@gmail.com> wrote:
> > Actually, the usual rule is that the base class destructor must
> > be either virtual or protected.  And of course, it is a
> > "programming standards" rule, not something imposed by the
> > standard.
> > [...]

> I may have either misunderstood you or do not understand how STL
> containers work, but don't STL containers call their stored objects`
> destructors? Doesn't this require the destructors to be public?

Yes. The point of having protected destructors is to disable deleting
objects through base class pointers and to avoid slicing.

class A {
protected:
A~() {}
};

class B : public A {};

B q; // OK, B::~B() is public
B* y = new B;
A x = *y; // ill-formed
A* p = y; // OK, *y is an A
delete p; // ill-formed

You can still create a vector<B> object.


Cheers!
SG

zr

unread,
Dec 14, 2008, 1:13:42 PM12/14/08
to

In what cases would deleting the derived using a base pointer is
undesirable? Is there any convincing example?

Martin Drautzburg

unread,
Dec 14, 2008, 4:43:15 PM12/14/08
to
Juha Nieminen wrote:

> However, if you go and needlessly make the destructor of "Pixel"
> virtual, the memory consumption will double (or triple if you are
> compiling to a 64-bit system, where pointers are 8 bytes large).

> Because the design principle of the C++ language is "you don't pay


> for what you don't use".

Thanks for that explanation. I understand your point.

Still I have my doubts that this would justify making "virtual"
non-default just because there are exreme cases where the memory
overhead just gets too much. I mean after all, the first mature
graphical user interfaces were written in Smalltalk which does not have
this notion of "virtual" (everything is virtual there). So it seems you
can manipulate pixels in a "virtual" world quite successfully.

Well if you are rendering Star Wars scenes, you might be happy about
non-virtual functions. But again that's an exreme case.

I suppose this is one of the issues which has been beaten to death in
various forums. So accept my apologies for brining it up again.

James Kanze

unread,
Dec 15, 2008, 4:46:58 AM12/15/08
to
On Dec 14, 7:13 pm, zr <zvir...@gmail.com> wrote:
> On Dec 14, 7:03 pm, SG <s.gesem...@gmail.com> wrote:
> > On 14 Dez., 13:31, zr <zvir...@gmail.com> wrote:

> > > On Dec 12, 11:41 am, James Kanze <james.ka...@gmail.com> wrote:
> > > > Actually, the usual rule is that the base class
> > > > destructor must be either virtual or protected. And of
> > > > course, it is a "programming standards" rule, not
> > > > something imposed by the standard.
> > > > [...]
> > > I may have either misunderstood you or do not understand
> > > how STL containers work, but don't STL containers call
> > > their stored objects` destructors? Doesn't this require
> > > the destructors to be public?

Objects in a standard container must have publically accessible
destructors, yes. They also must be copiable and assignable: in
sum, they must have value semantics. Which means that they
almost certainly aren't polymorphic.

> > Yes. The point of having protected destructors is to disable
> > deleting objects through base class pointers and to avoid
> > slicing.

> > class A {
> > protected:
> > A~() {}
> > };

> > class B : public A {};

> > B q; // OK, B::~B() is public
> > B* y = new B;
> > A x = *y; // ill-formed
> > A* p = y; // OK, *y is an A
> > delete p; // ill-formed

> > You can still create a vector<B> object.

> In what cases would deleting the derived using a base pointer


> is undesirable? Is there any convincing example?

Objects derived from std::iterator. Just about any time, in
fact, where inheritance is not being used for polymorphism.

Cases where there are pre-conditions on destruction. (This is
often the case for entity objects.) Client code doesn't delete;
it calls a member function, which validates the pre-conditions
before deleting the object. Or more generally, cases where the
lifetime is managed by the object itself.

James Kanze

unread,
Dec 15, 2008, 4:55:26 AM12/15/08
to
On Dec 14, 1:35 am, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:

> James Kanze wrote:
> > When you declare a function virtual, you've opened a hole
> > with regards to your class invariants, and increased the
> > chances for error.

> Wow, that's an interesting point (and well phrased). I'll have
> to think about that.

> > So you don't do it unless it serves a purpose, and usually,
> > you don't do it for public functions, which can be called by
> > anyone.

> Okay, I understand we have two different philosophies here.
> What I question in your philosophy is that you assume that the
> author of a class can forsee it's future use. That's kind of a
> pessimistic way of seeing things. It focusses on preventing
> programmers from making mistakes, rather than enabling them to
> do things *right*.

It's not pessimism, it's design. A class can't be everything to
everyone; it can only be what it was designed for. If I design
an interface Socket, for example, it can't really be used to
implement a window in a GUI system. If I design a class which
has certain invariants, then it can't be used in a way that
invalidates those invariants; those invariants are guarantees to
client code.

And such contracts are necessary if the programmer is to do
things right. How can you write code which uses the class if
you don't have guarantees concerning its contract?

> Declaring classes final always seemed kind of rude to me.

It's essential if you want to write working programs.

> Who am I to decide that nobody will come up with a good idea
> for subclassing my class.

Unless you carefully design the class with subclassing in mind,
any subclass will break your class, and break client code using
it.

> This person could even be me, one year in the future. You need
> some enomous foresight to decide that correctly. And if your
> class shouldn't be subclassed for really obvious reasons, then
> that thing shouldn't be a class in the first place.

And what should it be, then?

> But I understand you "contract" approach. Not limiting a
> class'es usage by declaring everything public and virtual
> isn't much of a conract. You want statements like "do not use
> indoors" attached to a class, where I'd say: "let them use it
> indoors, if they know what they're doing".

You've got your analogy backwards. The purpose of the contract
is to provide the necessary guarantees to the client code. So
that they can use it where ever appropriate. It's really part
of the basics of OO design.

James Kanze

unread,
Dec 15, 2008, 5:06:36 AM12/15/08
to
On Dec 14, 2:40 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Martin Drautzburg wrote:
[...]

> Practical example: Suppose you have a class named "Pixel",
> which contains four unsigned char members: red, green, blue
> and alpha. As it is, one instantiation of this class will
> require 4 bytes of memory. If you, for example, represent an
> image as a std::vector<Pixel>, the memory consumption will be
> the amount of pixels times 4 bytes.

> However, if you go and needlessly make the destructor of
> "Pixel" virtual, the memory consumption will double (or triple
> if you are compiling to a 64-bit system, where pointers are 8
> bytes large).

Quadruple, in fact, on most systems, because of alignment
considerations. Drop the alpha component, and I have
sizeof(Pixel) == 3 with no virtual functions; sizeof(Pixel) ==
16 with a virtual destructor.

> It is quite unlikely that you will ever inherit anything from
> "Pixel" (especially if your basic datatype is
> std::vector<Pixel>, which does not in itself support
> specialization of the elements), so making any function
> virtual would only be a waste of memory.

It's a value type. It supports assignment. We all know that
polymorphism and assignment don't mix. Declaring anything
virtual in a value (including the destructor) is probably a sign
of poor design: is it a value, or isn't it? Even the author
doesn't know.

For me, this is an even more important issue than the size
(although for things like Pixel, size does matter).

> Another price to pay is that calling a virtual function is
> slightly slower than calling a non-virtual one. This might not
> be relevant in most cases, but with small functions which get
> called millions of times per second, it might make a
> difference.

Get a compiler with a better optimizer:-). (Good compilers can
solve this one.)

> > So I keep thinking: why not just make *every* function and
> > *every* destructor virtual (and rename "virtual" to
> > "natural"), if that relieves the headaches.

> Because it causes overhead, especially with very small classes.

> > I wonder what is the reason for this "virtual" complexity.

> Because the design principle of the C++ language is "you don't
> pay for what you don't use".

Because independently of C++, a good design concept is "say what
you mean, and mean what you say". In C++, a virtual destructor
is generally understood as saying "derive from me". If that's
what you want to say, fine, but then you should probably also
ensure that there is no public assignment operator (and that if
copy is supported, it is via a virtual clone function, and not
just a public copy constructor).

The size issue is relevant for some classes---your example of
Pixel is a good one. But the design issue is relevant for all
classes.

Martin Drautzburg

unread,
Dec 15, 2008, 6:52:20 AM12/15/08
to
James Kanze wrote:

> On Dec 14, 1:35 am, Martin Drautzburg <Martin.Drautzb...@web.de>

>> But I understand you "contract" approach. Not limiting a


>> class'es usage by declaring everything public and virtual
>> isn't much of a conract. You want statements like "do not use
>> indoors" attached to a class, where I'd say: "let them use it
>> indoors, if they know what they're doing".
>
> You've got your analogy backwards. The purpose of the contract
> is to provide the necessary guarantees to the client code. So
> that they can use it where ever appropriate. It's really part
> of the basics of OO design.

I think you're going over the edge here. There may be good reasons to
limit a classes future use, but these seem to be more related to the
inner workings of C++ and not a matter of "basic OO design". Tell that
a Smalltalk guru an he will probably tell you that C++ is not OO at
all.

Actually I'd say that subclassing is *the* primary thing in OO. Without
subclassing you are merely working with abstract data types. If you are
saying that working with ADTs is in many cases more safe than working
with classes, then you are probably right. I would really hesitate to
subclass e.g. a file descriptor. But then again, if I ever felt the
need to teach a file descriptor new tricks, I would much rather create
a subclass that hacking my operating system kernel.

But I am seeing this from a semantic point of view. There are things in
the real world, which can be classified and specialized. You can say "a
cat is special kind of animal". In OO languages this relationship ("Is
a special kind of") can be expressed via sublassing. In the real world
there are very few concepts which cannot be specialized (maybe Life,
Death and Existance are exceptions). This is why I am always puzzeled
when classes are declared final, because it basicly states that "there
can never be a special kind of this thing".

Message has been deleted

Paavo Helde

unread,
Dec 15, 2008, 4:31:06 PM12/15/08
to
James Kanze <james...@gmail.com> kirjutas:

> It's not pessimism, it's design. A class can't be everything to
> everyone; it can only be what it was designed for. If I design
> an interface Socket, for example, it can't really be used to
> implement a window in a GUI system.

It's curious that you chose these exact example classes. Namely, the MFC
library CSocket class is implemented by an invisible top-level window in
the Windows GUI system. So it seems a window could actually be used for
implementing a socket! (To be honest, not very well, this can easily cause
a lot of problems, like PDF documents not opening any more, or other random
applications getting blocked. I learned this in the hard way by debugging
someone else's code, and I am allergic to the word CSocket since then.)

Paavo



Andrey Tarasevich

unread,
Dec 15, 2008, 6:52:58 PM12/15/08
to
DavidW wrote:
> Hello,

>
> I just to confirm a rule.
>
> class B
> {
> public:
> virtual ~B() {}
> virtual void f();
> };
>
> class D : public B
> {
> public:
> void f();
> };
>
> The virtual ~B() is necessary because B has at least one virtual function, but
> an explicit d'tor is not required in derived classes. Correct?

No. Virtual destructor is only really necessary when your design calls
for polymorphic destruction of objects. In your case, if you intend to
permit deletion of 'D' objects through pointers of 'B*' type, then you
need a virtual destructor. Otherwise, you don't need it.

The rule "if you have at least one virtual function, then you need the
virtual destructor" is one of those "C++ for dummies" rules, which might
work as a bit of canned knowledge for a beginner, but has very little or
no value for an established programmer.

One can correctly note that in a typical implementation adding a virtual
destructor to a class that already has virtual functions carries no
additional overhead. I.e. the logic of "it's free, so let's just have it
anyway, regardless of whether we really need it" works here. But still
it is in no way correct to say that the presence of a virtual function
somehow makes it "necessary" (as you said in your post) to declare the
destructor as virtual.

--
Best regards,
Andrey Tarasevich

James Kanze

unread,
Dec 16, 2008, 6:06:52 AM12/16/08
to
On Dec 15, 12:52 pm, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:

> James Kanze wrote:
> > On Dec 14, 1:35 am, Martin Drautzburg <Martin.Drautzb...@web.de>
> >> But I understand you "contract" approach. Not limiting a
> >> class'es usage by declaring everything public and virtual
> >> isn't much of a conract. You want statements like "do not
> >> use indoors" attached to a class, where I'd say: "let them
> >> use it indoors, if they know what they're doing".

> > You've got your analogy backwards. The purpose of the
> > contract is to provide the necessary guarantees to the
> > client code. So that they can use it where ever
> > appropriate. It's really part of the basics of OO design.

> I think you're going over the edge here. There may be good
> reasons to limit a classes future use, but these seem to be
> more related to the inner workings of C++ and not a matter of
> "basic OO design". Tell that a Smalltalk guru an he will
> probably tell you that C++ is not OO at all.

It's not a question of "limiting a class". It's a question of
establishing a definition of what the interface does, so that
client code can use it. Today, and in the future.

> Actually I'd say that subclassing is *the* primary thing in
> OO.

It seems like every OO guru has a different definition of OO:-).
Still, I tend to agree that inheritance and dynamic dispatch are
an important part. But that doesn't mean no constraints. The
interface defines a contract, which all of the derived classes
must fulfill if the interface is to be usable. And once you
have an implementation, further derivation is really only
acceptable if the implementation is designed for it (e.g.
template method pattern); generally, the implementation of the
different virtual functions will be designed to work together,
and overriding one, without overriding all, will cause class
invariants to fail unless the author of the implementation has
taken this possibility into consideration.

And of course, not everything is, nor should be, OO. Value
semantics and inheritance don't go well to gether, for example;
so-called "pure" OO languages generally avoid the problem by not
supporting values at all, but that just means you need some
extra rules to simulate them.

> Without subclassing you are merely working with abstract data
> types. If you are saying that working with ADTs is in many
> cases more safe than working with classes, then you are
> probably right. I would really hesitate to subclass e.g. a
> file descriptor. But then again, if I ever felt the need to
> teach a file descriptor new tricks, I would much rather create
> a subclass that hacking my operating system kernel.

Wouldn't implementing a new class, which wraps the file
descripter, make more sense? (In practice, you generally can't
modify the semantics of a file descriptor without modifying
kernel code. For good reasons.)

> But I am seeing this from a semantic point of view. There are
> things in the real world, which can be classified and
> specialized. You can say "a cat is special kind of animal". In
> OO languages this relationship ("Is a special kind of") can be
> expressed via sublassing. In the real world there are very few
> concepts which cannot be specialized (maybe Life, Death and
> Existance are exceptions). This is why I am always puzzeled
> when classes are declared final, because it basicly states
> that "there can never be a special kind of this thing".

I'm not sure that this applies. A base class (in a statically
typed language like C++ or Java, at least) defines a concrete,
bound interface, with a contract. The contract is necessary in
order for client code to use that interface. In the real world,
cats don't care whether they adhere to any contract or not; it's
up to you (or the cat) to cope with it. (For example, the class
Cat might implement a function legCount() to return 4, and a
function walk() which depended on legCount() == 4 in order to
work. In real life, there are cats that have lost a leg.)

James Kanze

unread,
Dec 16, 2008, 6:13:05 AM12/16/08
to
On Dec 15, 10:31 pm, Paavo Helde <pa...@nospam.please.ee> wrote:
> James Kanze <james.ka...@gmail.com> kirjutas:

> > It's not pessimism, it's design. A class can't be
> > everything to everyone; it can only be what it was designed
> > for. If I design an interface Socket, for example, it can't
> > really be used to implement a window in a GUI system.

> It's curious that you chose these exact example classes.

Just the first random idea that came to my mind.

> Namely, the MFC library CSocket class is implemented by an
> invisible top-level window in the Windows GUI system. So it
> seems a window could actually be used for implementing a
> socket! (To be honest, not very well, this can easily cause a
> lot of problems, like PDF documents not opening any more, or
> other random applications getting blocked. I learned this in
> the hard way by debugging someone else's code, and I am
> allergic to the word CSocket since then.)

In other words, the base class of CSocket makes guarantees that
CSocket can't maintain. A major design error, if this is really
the case. (I know nothing of MFC, so I can't really judge, but
the online documentation says that CSocket derives from
CAsynSocket, which derives from CObject. Which seems reasonable
*IF* you can trust the names; obviously, if CObject guaranteed
that all CObject's can open a PDF document, then CSocket fails.)

Paavo Helde

unread,
Dec 16, 2008, 1:48:25 PM12/16/08
to
James Kanze <james...@gmail.com> kirjutas:

> On Dec 15, 10:31 pm, Paavo Helde <pa...@nospam.please.ee> wrote:
>> James Kanze <james.ka...@gmail.com> kirjutas:
>
>> > It's not pessimism, it's design. A class can't be
>> > everything to everyone; it can only be what it was designed
>> > for. If I design an interface Socket, for example, it can't
>> > really be used to implement a window in a GUI system.
>
>> It's curious that you chose these exact example classes.
>
> Just the first random idea that came to my mind.
>
>> Namely, the MFC library CSocket class is implemented by an
>> invisible top-level window in the Windows GUI system. So it
>> seems a window could actually be used for implementing a
>> socket! (To be honest, not very well, this can easily cause a
>> lot of problems, like PDF documents not opening any more, or
>> other random applications getting blocked. I learned this in
>> the hard way by debugging someone else's code, and I am
>> allergic to the word CSocket since then.)
>
> In other words, the base class of CSocket makes guarantees that
> CSocket can't maintain. A major design error, if this is really
> the case. (I know nothing of MFC, so I can't really judge, but
> the online documentation says that CSocket derives from
> CAsynSocket, which derives from CObject. Which seems reasonable
> *IF* you can trust the names; obviously, if CObject guaranteed
> that all CObject's can open a PDF document, then CSocket fails.)

No, the CSocket system itself kind of works; the other applications are
those which are suffering.

This is actually not an example of implementation of the interface, the
interface is probably OK (never cared to study in detail). Instead,
CSosket creates a window from inside its code and relies on it internally
quite a lot, so that's what I called "implemented by a window".

More in detail, CSocket is designed to work in a single-threaded
application and behave like its Accept() were blocking. What really
happens is that it is executing the window message pump from inside
Accept(). In order to keep the message loop alive and to respond to
notifications it creates a hidden window and puts a timer on it. So
actually also the timer is implemented as a window!

So far so good. Why shouldn't everything be a window, especially on
Windows. But what happens next is that some programmer not quite tuned to
the MFC mindset reads CSocket documentation and sees "blocking socket".
Aha, I will have to create a worker thread to not held my main thread
blocked! So he goes and creates a worker thread, which reads some message
from the socket and then goes into some lengthy calculations. Now that
happens that the user wants to open a PDF or some other document at the
same time. This often involves a step where all top-level application
windows are queried by Windows if they want to handle such an event. Also
the hidden CSosket window is queried. However, as it is created in a
worker thread which is currently busy with some other tasks, there is no
windows message loop running, and thus the whole operation is blocked.
What's more, the programmer does not have a slightest idea he might have
done something wrong (as the CSocket documentation does not mention such
things at all).

I think there was some timeout, but in case of many alive CSocket objects
the timeout grew very long.

Sorry about being so off-topic, but I think this is a nice negative
design example!

Paavo

DavidW

unread,
Dec 16, 2008, 3:45:47 PM12/16/08
to
Andrey Tarasevich wrote:
> DavidW wrote:
>> Hello,
>>
>> I just to confirm a rule.
>>
>> class B
>> {
>> public:
>> virtual ~B() {}
>> virtual void f();
>> };
>>
>> class D : public B
>> {
>> public:
>> void f();
>> };
>>
>> The virtual ~B() is necessary because B has at least one virtual
>> function, but an explicit d'tor is not required in derived classes.
>> Correct?
>
> No. Virtual destructor is only really necessary when your design calls
> for polymorphic destruction of objects. In your case, if you intend to
> permit deletion of 'D' objects through pointers of 'B*' type, then you
> need a virtual destructor. Otherwise, you don't need it.
>
> The rule "if you have at least one virtual function, then you need the
> virtual destructor" is one of those "C++ for dummies" rules, which
> might work as a bit of canned knowledge for a beginner, but has very
> little or no value for an established programmer.

It would almost always be true, though, would it not? Once you have any virtual
function you are assuming that it will be needed somewhere, i.e., that somewhere
a base pointer or reference will be used to call it. Therefore, you could not
rule out that somewhere the object might be deleted similarly. Except for very
special purposes one cannot predict how objects of the class will be deleted.


Pete Becker

unread,
Dec 16, 2008, 5:21:33 PM12/16/08
to
On 2008-12-16 15:45:47 -0500, "DavidW" <n...@email.provided> said:

> Andrey Tarasevich wrote:
>>
>> The rule "if you have at least one virtual function, then you need the
>> virtual destructor" is one of those "C++ for dummies" rules, which
>> might work as a bit of canned knowledge for a beginner, but has very
>> little or no value for an established programmer.
>
> It would almost always be true, though, would it not?

Yes.

> Once you have any virtual
> function you are assuming that it will be needed somewhere, i.e., that
> somewhere
> a base pointer or reference will be used to call it. Therefore, you could not
> rule out that somewhere the object might be deleted similarly. Except for very
> special purposes one cannot predict how objects of the class will be deleted.

The issue isn't predicting, but designing. If I make a design decision
that my class can be used as a base class but that I'm not going to
support deleting derived types through a pointer to my class, and
document that decision, then if some user ignores the documentation
they deserve whatever happens to them. I predict that they won't be
happy.

Andrey Tarasevich

unread,
Dec 16, 2008, 5:55:48 PM12/16/08
to
DavidW wrote:
>>
>> The rule "if you have at least one virtual function, then you need the
>> virtual destructor" is one of those "C++ for dummies" rules, which
>> might work as a bit of canned knowledge for a beginner, but has very
>> little or no value for an established programmer.
>
> It would almost always be true, though, would it not? Once you have any virtual
> function you are assuming that it will be needed somewhere, i.e., that somewhere
> a base pointer or reference will be used to call it.

Not necessarily! You are assuming that polymorphism is always "external"
(so to say) i.e. the polymorhic behavior is always immediately and
directly accessible to the client code: the client code accesses derived
classes through base-class-typed pointers.

In reality though this is not necessarily the case. Take, for example,
the 'Template Method' design pattern, where primitive operations in a
generic algorithm would normally be represented by virtual functions. In
many cases the end-objects built with this pattern will not be seen as
polymorphic by the client code, it's only their inner workings that rely
on run-time polymorphism. The virtual functions in this case would most
likely be protected.

Which brings us to the more precise version of the rule in question:
"once you have any _public_ virtual function, you are assuming that it

will be needed somewhere, i.e., that somewhere a base pointer or
reference will be used to call it".

> Therefore, you could not
> rule out that somewhere the object might be deleted similarly. Except for very
> special purposes one cannot predict how objects of the class will be deleted.

Sorry, this bit puts the horse behind the carriage. It is the
responsibility of the client code to make sure that my class is used in
full agreement with what it was designed for by me, the author of the
class. It is great when the language provides me with the means that let
me to express my intentions through the language constructs, desirably
making the compiler to detect and prevent any misuses early, at the
compile-time. Alas, there's no language that can cover everything. Some
requirements I'll still have to explain in the comments and/or in the
supplied documentation. With any language there will always be ways to
go around the restrictions, there will always be ways to abuse the
class, use it incorrectly. Catering to those who abuse it is not the
right thing to do. If my class is not intended to be destroyed
polymorphically, I'll just say so and I won't care to "predict" how
objects of the class will be deleted by this who don't care to
familiarize themselves with the specification.

DavidW

unread,
Dec 16, 2008, 6:42:22 PM12/16/08
to
Pete Becker wrote:
> On 2008-12-16 15:45:47 -0500, "DavidW" <n...@email.provided> said:
>
>> Andrey Tarasevich wrote:
>>>
>>> The rule "if you have at least one virtual function, then you need
>>> the virtual destructor" is one of those "C++ for dummies" rules,
>>> which might work as a bit of canned knowledge for a beginner, but
>>> has very little or no value for an established programmer.
>>
>> It would almost always be true, though, would it not?
>
> Yes.
>
>> Once you have any virtual
>> function you are assuming that it will be needed somewhere, i.e.,
>> that somewhere
>> a base pointer or reference will be used to call it. Therefore, you
>> could not rule out that somewhere the object might be deleted
>> similarly. Except for very special purposes one cannot predict how
>> objects of the class will be deleted.
>
> The issue isn't predicting, but designing. If I make a design decision
> that my class can be used as a base class but that I'm not going to
> support deleting derived types through a pointer to my class, and
> document that decision, then if some user ignores the documentation
> they deserve whatever happens to them. I predict that they won't be
> happy.

Okay, but I would suggest that your "documentation" consist of a protected
destructor, as was suggested elsewhere. public/protected/private are there to
enforce design decisions, presumably because programmers can't be relied upon to
be voluntarily compliant with a design decision that is communicated only with a
comment.


James Kanze

unread,
Dec 17, 2008, 3:57:48 AM12/17/08
to

> >> Andrey Tarasevich wrote:

> > Yes.

"Trust is good. Verification is better." But that's why you
have code reviews.

Seriously, having the compiler enforce something is always good.
Extra effort is always bad. Depending on the case, the extra
effort necessary for such verification might outweigh the
benefits. In this particular case, you can't forget that making
the destructor protected means that you can't destruct an
instance of the base class. Sometimes, limiting destruction is
what you want---you want to enforce preconditions before
destruction. (Note that this means that you can't have
instances with local or static lifetime.) Other times, it makes
no sense to have an instance of the class to begin with (e.g.
std::iterator<>). In the first case, making the destructor
protected is probably a very good solution. In the second, it
has to be weighed against the fact that making the destructor
protected means that no derived class can have a trivial
destructor; at least in the case of std::iterator, this means
that the committee was right in not providing it with a
protected destructor. (Perhaps in the new version: "protected:
~iterator() = default ;"?)

Pete Becker

unread,
Dec 17, 2008, 7:23:20 AM12/17/08
to

My documentation is a text presentation that, among other things,
documents the design decision: don't delete derived types through a
pointer to my class. A protected destructor is code, not documentation.
A comment is code, not documentation.

It's not my job to "enforce" design decisions that I've made. It's the
user's job to understand the class well enough to use it correctly.
Programmers who don't bother to read documentation aren't really
programmers, just warm bodies filling seats.

Bart van Ingen Schenau

unread,
Dec 17, 2008, 8:23:30 AM12/17/08
to
On Dec 14, 10:43 pm, Martin Drautzburg <Martin.Drautzb...@web.de>
wrote:

> Juha Nieminen wrote:
> > However, if you go and needlessly make the destructor of "Pixel"
> > virtual, the memory consumption will double (or triple if you are
> > compiling to a 64-bit system, where pointers are 8 bytes large).
> > Because the design principle of the C++ language is "you don't pay
> > for what you don't use".
>
> Thanks for that explanation. I understand your point.
>
> Still I have my doubts that this would justify making "virtual"
> non-default just because there are exreme cases where the memory
> overhead just gets too much. I mean after all, the first mature
> graphical user interfaces were written in Smalltalk which does not have
> this notion of "virtual" (everything is virtual there). So it seems you
> can manipulate pixels in a "virtual" world quite successfully.

The justification for not making virtual the default is a very basic
design principle of C++: You don't pay for what you don't use.

As not everyone uses C++ to write OO programs and C++ does not prefer
one methodology over another (as long as both are supported by the
language), there is no reason that the non-OO programs should pay a
price for supporting OO features they intentionally don't use.

>
> Well if you are rendering Star Wars scenes, you might be happy about
> non-virtual functions. But again that's an exreme case.

Do you conside embedded devices, with only a few K memory extreme
cases as well?
C++ is getting quite a foot on the ground in the embedded world now,
and memory consumtion is always a big issue there.

>
> I suppose this is one of the issues which has been beaten to death in
> various forums. So accept my apologies for brining it up again.

Bart v Ingen Schenau

James Kanze

unread,
Dec 17, 2008, 8:34:31 AM12/17/08
to
On Dec 17, 2:23 pm, Bart van Ingen Schenau

<Bart.van.Ingen.Sche...@ict.nl> wrote:
> On Dec 14, 10:43 pm, Martin Drautzburg <Martin.Drautzb...@web.de>
> wrote:

> > Juha Nieminen wrote:
> > > However, if you go and needlessly make the destructor of "Pixel"
> > > virtual, the memory consumption will double (or triple if you are
> > > compiling to a 64-bit system, where pointers are 8 bytes large).
> > > Because the design principle of the C++ language is "you don't pay
> > > for what you don't use".

> > Thanks for that explanation. I understand your point.

> > Still I have my doubts that this would justify making
> > "virtual" non-default just because there are exreme cases
> > where the memory overhead just gets too much. I mean after
> > all, the first mature graphical user interfaces were written
> > in Smalltalk which does not have this notion of "virtual"
> > (everything is virtual there). So it seems you can
> > manipulate pixels in a "virtual" world quite successfully.

> The justification for not making virtual the default is a very
> basic design principle of C++: You don't pay for what you
> don't use.

The real justification for not making virtual the default is
that it would be wrong most of the time, and inconsistent with
the other design decisions. From a design standpoint, the basic
default of C++ is that classes have value semantics; if you want
something else, you take appropriate actions (declaring
functions virtual, etc.). And a class with value semantics has
no need of a virtual destructor; in fact, a virtual destructor
gives the wrong message about the class.

DavidW

unread,
Dec 17, 2008, 4:11:09 PM12/17/08
to

That may be, but if your aim is to have the highest possible standard of
software in the world, then documentation alone won't do, since it's a
statistical certainty that there will be programmers - sorry, warm bodies
filling seats who write programs - who will ignore it.


DavidW

unread,
Dec 17, 2008, 4:24:37 PM12/17/08
to
Bart van Ingen Schenau wrote:
> On Dec 14, 10:43 pm, Martin Drautzburg <Martin.Drautzb...@web.de>
> wrote:
>> Juha Nieminen wrote:
>>> However, if you go and needlessly make the destructor of "Pixel"
>>> virtual, the memory consumption will double (or triple if you are
>>> compiling to a 64-bit system, where pointers are 8 bytes large).
>>> Because the design principle of the C++ language is "you don't pay
>>> for what you don't use".
>>
>> Thanks for that explanation. I understand your point.
>>
>> Still I have my doubts that this would justify making "virtual"
>> non-default just because there are exreme cases where the memory
>> overhead just gets too much. I mean after all, the first mature
>> graphical user interfaces were written in Smalltalk which does not
>> have this notion of "virtual" (everything is virtual there). So it
>> seems you can manipulate pixels in a "virtual" world quite
>> successfully.
>
> The justification for not making virtual the default is a very basic
> design principle of C++: You don't pay for what you don't use.

Yes. Consider the difference between a long, tight loop calling a virtual
function and a long, tight loop calling a small inline function.

>
> As not everyone uses C++ to write OO programs and C++ does not prefer
> one methodology over another (as long as both are supported by the
> language), there is no reason that the non-OO programs should pay a
> price for supporting OO features they intentionally don't use.
>
>>
>> Well if you are rendering Star Wars scenes, you might be happy about
>> non-virtual functions. But again that's an exreme case.

But cases where you don't want to pay for virtual functions are not extreme.
I've written computing-intensive programs that would slow down massively if all
calls of class member functions had to be virtual.

Pete Becker

unread,
Dec 17, 2008, 5:36:24 PM12/17/08
to
On 2008-12-17 16:11:09 -0500, "DavidW" <n...@email.provided> said:

>
> That may be, but if your aim is to have the highest possible standard of
> software in the world, then documentation alone won't do, since it's a
> statistical certainty that there will be programmers - sorry, warm bodies
> filling seats who write programs - who will ignore it.

If your goal is to write code that can be used by incompetent
programmers, I wish you the best of luck. I find it hard enough to
write code that can be used by competent ones.

James Kanze

unread,
Dec 18, 2008, 4:46:28 AM12/18/08
to
On Dec 17, 10:11 pm, "DavidW" <n...@email.provided> wrote:
> Pete Becker wrote:
> > On 2008-12-16 18:42:22 -0500, "DavidW" <n...@email.provided> said:
> >> Pete Becker wrote:
> >>> On 2008-12-16 15:45:47 -0500, "DavidW" <n...@email.provided> said:

[...]


> > My documentation is a text presentation that, among other
> > things, documents the design decision: don't delete derived
> > types through a pointer to my class. A protected destructor
> > is code, not documentation. A comment is code, not
> > documentation.

Unless you're using Doxygen:-).

Seriously, there should be a relationship between the comments
and the code. And there's nothing wrong with enforcing the
contract, when feasable; if the contract says that client code
should not destruct instances of the object (only reasonable if
all instances are allocated dynamically), then declaring the
destructor protected (or private, if you're not supporting
inheritance) seems correct, just as it would be for any other
function. (Surely, Pete, you're not saying that we shouldn't
use private and public, because the documentation should be
enough.)

> > It's not my job to "enforce" design decisions that I've
> > made. It's the user's job to understand the class well
> > enough to use it correctly. Programmers who don't bother to
> > read documentation aren't really programmers, just warm
> > bodies filling seats.

> That may be, but if your aim is to have the highest possible
> standard of software in the world, then documentation alone
> won't do, since it's a statistical certainty that there will
> be programmers - sorry, warm bodies filling seats who write
> programs - who will ignore it.

That's why you have code reviews. Such programmers will either
change their ways, or won't be allowed to work on code.

When feasable, I'm all in favor of using both suspenders and a
belt: document the restrictions, and implement the code such
that violating them causes a compiler error. But it's not
always feasable, and making the destructor protected has
additional impact which has to be considered. If it has no
extra cost, fine, but otherwise, you have to weigh the costs.

Pete Becker

unread,
Dec 18, 2008, 7:50:33 AM12/18/08
to
On 2008-12-18 04:46:28 -0500, James Kanze <james...@gmail.com> said:

> On Dec 17, 10:11 pm, "DavidW" <n...@email.provided> wrote:
>> Pete Becker wrote:
>>> On 2008-12-16 18:42:22 -0500, "DavidW" <n...@email.provided> said:
>>>> Pete Becker wrote:
>>>>> On 2008-12-16 15:45:47 -0500, "DavidW" <n...@email.provided> said:
>
> [...]
>>> My documentation is a text presentation that, among other
>>> things, documents the design decision: don't delete derived
>>> types through a pointer to my class. A protected destructor
>>> is code, not documentation. A comment is code, not
>>> documentation.
>
> Unless you're using Doxygen:-).
>
> Seriously, there should be a relationship between the comments
> and the code.

Sure. But the claim that you snipped was that my documentation
consisted of a protected destructor and comments. The user of a class
shouldn't have to read the code and comments to figure out how to use
it.

> And there's nothing wrong with enforcing the
> contract, when feasable; if the contract says that client code
> should not destruct instances of the object (only reasonable if
> all instances are allocated dynamically), then declaring the
> destructor protected (or private, if you're not supporting
> inheritance) seems correct, just as it would be for any other
> function. (Surely, Pete, you're not saying that we shouldn't
> use private and public, because the documentation should be
> enough.)

Of course not. But that's not documentation.

DavidW

unread,
Dec 18, 2008, 4:02:24 PM12/18/08
to
James Kanze wrote:
> On Dec 17, 10:11 pm, "DavidW" <n...@email.provided> wrote:
>> Pete Becker wrote:
>
>>> It's not my job to "enforce" design decisions that I've
>>> made. It's the user's job to understand the class well
>>> enough to use it correctly. Programmers who don't bother to
>>> read documentation aren't really programmers, just warm
>>> bodies filling seats.
>
>> That may be, but if your aim is to have the highest possible
>> standard of software in the world, then documentation alone
>> won't do, since it's a statistical certainty that there will
>> be programmers - sorry, warm bodies filling seats who write
>> programs - who will ignore it.
>
> That's why you have code reviews. Such programmers will either
> change their ways, or won't be allowed to work on code.

Not everyone can afford code reviews. In fact, there are very many
single-programmer projects in small companies.


James Kanze

unread,
Dec 18, 2008, 6:17:27 PM12/18/08
to

The question is rather, can anyone afford to not have them.
They reduce the cost of developing software significantly.

> In fact, there are very many single-programmer projects in
> small companies.

Effective programming is a team activity. There's no such thing
as a single-programmer writing correct code.

Pete Becker

unread,
Dec 19, 2008, 8:51:56 AM12/19/08
to
On 2008-12-18 18:17:27 -0500, James Kanze <james...@gmail.com> said:

> On Dec 18, 10:02 pm, "DavidW" <n...@email.provided> wrote:
>
>> Not everyone can afford code reviews.
>
> The question is rather, can anyone afford to not have them.
> They reduce the cost of developing software significantly.

"If you don't have time to do it right, when will you have time to fix it?"

Martin Drautzburg

unread,
Dec 20, 2008, 6:37:40 AM12/20/08
to
James Kanze wrote:

> Wouldn't implementing a new class, which wraps the file
> descripter, make more sense? (In practice, you generally can't
> modify the semantics of a file descriptor without modifying
> kernel code. For good reasons.)

I see what you mean. In that case you would follow the classic "library"
pattern, i.e. you let "new code call old code". The virtue of
inheritance however is that you can have "old code call new code".

I am not sure if allowing old code to call new code really creates more
problems than it solves. It definitly creates a set of new problems,
most notably that you need to know more about the inner workings of the
classes you derive from. The interface is a lot broader and broad
interfaces violate the idea of information hiding to some extent.

On the other hand virtual inheritance allows more aggressive
refactoring, i.e. you have more options to avoid duplicated code.
Duplicated code also creates a whole set of new problems.

An from a semantic point of view, virtual inheritance just seems more
natural to me. If I have a class HandicappedCat where legCount()
returns 3 instead of 4 (which would have been returned by the
superclass Cat), then so be it. If a variable of type Cat contains a
handicappedCat then I would be very surprised if the legCount()
returned 4, just because the variable is of that type where the cat in
question really only has 3 legs.

0 new messages