Topic: C++ 'philosophy' question, Constructors/Destructors


Author: Christopher Smith <ccas@pacbell.net>
Date: 2000/07/18
Raw View
Ken Hagan <K.Hagan@thermoteknix.co.uk> wrote in message
news:newscache$omc9wf$h71$1@firewall.thermoteknix.co.uk...
> "Leonid Portnoy" <lp178@columbia.edu> wrote in message
> news:394a5536.29331042@news.columbia.edu...
> >
> <snipped a lot of stuff on wanting 2 dtors...>
>> If there could be many destructors, I would specify, in my base Bitmap
>> class, a second destructor which would not attempt to free memory.
>> Let's say it would be called if constructor #2 of the base class was
>> used to create the object. This constructor would not allocate any
>> memory but just initialize other members.
>
>> Then in the derived class's constructor, I would specify how to create
>> the base class (by calling constr. #2), and then when destroying my
>> derived class it would automatically call the appropriate destructor
>> (the one that doesn't free memory) of the base class...

>The second constructor and destructor are only needed if someone
>goes on to write the derived class. I have no objection to writing
>a class with a view to deriving certain related classes from it, but
>if I do this too much, I lose encapsulation. (The needs of the
>derived classes are now driving the design of the base class.)

And this second constructor does not fully construct the object -- it is
broken as the
memory doesnt point to anything!

Another problem is that absent a "assign destructor" statement of some kind
the only logical
counterpart to 1 destructor is to have 1 per constructor. And this makes the
normal case of many
constructors all going to the same internal state require tons of identical
code be maintained. Ick.

And if you really want to make code that changes the behavoir of the base
class variables, while not nice
you can just change the base class to allow you to do this with some kind of
flag variable. Of course, the best
solution if the needs of the class have changed such that memory mgmt of the
buffer should not be in the base is
to create a manager class family derived from a common base. Then you can
use virtual functions and inheritance to
have different types of buffers be handled 'the same way' from our class'
point of view but correctly, too.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: comeau@panix.com (Greg Comeau)
Date: 2000/06/20
Raw View
In article <UFkAN6AZDmT5EwHQ@robinton.demon.co.uk>,
Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
>In article <8ih5f2$8k1$1@panix2.panix.com>, Greg Comeau
><comeau@panix.com> writes
>>It was a design choice, that was a fundamental reason, which was
>>what you said: the automation.  Ctors and dtors are special,
>>and their semantics are a "conspiracy" between you and the compiler,
>>hence requiring some integrity of behavior to be maintained,
>>through exceptions, etc, whereas some of your other functions
>>are "just" from you.
>
>But it isn't really that different from the way that the ctors for
>objects passed by value are called on entry to the scope and the dtors
>are called on exit from that scope.

We definitely agree completely.  But somebody who doesn't like the
scope calls (though I don't think this include the OP),
in particular the dtor calls, won't agree, and so won't like the
automation of the base class behavior either :(

- Greg
--
Comeau Computing / Comeau C/C++ 4.2.42 (4.2.44 expected soon)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/06/17
Raw View
In article <394a5536.29331042@news.columbia.edu>, Leonid Portnoy
<lp178@columbia.edu> writes
>Any thoughts?

Yes, I think your view is fundamentally flawed. Exactly what is going to
deal with the base class after the derived class has been destroyed? The
whole point of C++ inheritance is that the derived object constructor is
responsible for the base class construction, nothing else knows of the
base class instance and so nothing else can destroy it. The derived
instance owns the base instance and has no way of passing that ownership
on. If you do not want that then you must not use any form of
inheritance.

Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/06/18
Raw View
Leonid Portnoy wrote:
>
> Hi,
>
>     What is the reason C++ automatically calls the destructor for the
> base class after calling the destructor for the derived class?

Because the base class subobject has to be destroyed, too.

>
>     Sometimes this is not needed, and can even be harmful. For
> example, I have a Bitmap class, that does operations on graphical
> data. It has an internal pointer to the graphics : 'void *data' as a
> member variable, which gets initialized (memory allocated for it) upon
> construction, and deallocated in the destructor.
>
>     Now, I wanted to write a DirectX bitmap class, which would perform
> the same graphical operations on data, except that the data would be
> stored in memory provided by DirectX. So it made sense to derive from
> the Bitmap class, and in the constructor obtain a pointer from DirectX
> API, and set 'data' to it.

Well, in an optimal OO world, the derived class doesn't have
access to the base class data...

>
>      However, now when I destroy this derived class, I  want to
> release the memory (again by using directX api), and to return. But
> instead, after this C++ calls the base class's destructor, which
> attempts to free the data as if it was regular memory. Obviously this
> causes problems.
>
>      Of course, I can set data=NULL, set flags, etc.. to prevent the
> base class's destructor from doing damage, but this seems like an
> inelegant solution.
>
>      This raises another question : Why does a class have only one
> destructor, but multiple constructors? Why not have multiple
> destructors, that will be called based on what constructor was used to
> create the object.
>
> If there could be many destructors, I would specify, in my base Bitmap
> class, a second destructor which would not attempt to free memory.
> Let's say it would be called if constructor #2 of the base class was
> used to create the object. This constructor would not allocate any
> memory but just initialize other members.
>
> Then in the derived class's constructor, I would specify how to create
> the base class (by calling constr. #2), and then when destroying my
> derived class it would automatically call the appropriate destructor
> (the one that doesn't free memory) of the base class...

There are several ways to solve this problem.

One solution is to say that "Memory based Bitmap" and
"ActiveX Bitmap" are actually two types of bitmap, and
therefore should be derived from a common base class
which does the common stuff:

class Bitmap
{
public:
  // everything the bitmaps have in common
protected:
  Bitmap(foo* data): bitmap_data(data) {}
  virtual ~Bitmap() {}
  foo* data;
};

class MemBitmap:
  public Bitmap
{
public:
  MemBitmap(): Bitmap(new foo[100]) {}
  ~MemBitmap() { delete[] data; }
  // possibly other differences
};

class ActiveXBitmap:
  public Bitmap
{
public:
  ActiveXBitmap(): Bitmap(GetActiveXMem(100)) {}
  ~ActiveXBitmap() { ReleaseActiveXMem(data); }
  // possibly other differences
};

However, this still has the disadvantage that the data
pointer has to be accessible to derived classes (virtual
functions are no solution, since they don't get called
from base class constructors/destructors).


A second approach is to use delegation:

class Allocator
{
public:
  virtual ~BitmapAllocator() {}
  virtual foo* get(size_t size);
  virtual void release(foo*);
};

class MemAllocator: public Allocator { ... };
class ActiveXAllocator: public Allocator { ... };

MemAllocator memalloc;
ActiveXAllocator actxalloc;

class Bitmap
{
public:
  Bitmap(Allocator& alloc):
    allocator(alloc), data(alloc.get(100)) {}
  ~Bitmap() { allocator.release(data); }
private:
  Allocator& allocator;
  foo* data;
};

void foo()
{
  Bitmap b1(memalloc); // doesn't use ActiveX
  Bitmap b2(actxalloc); // uses ActiveX
}

Those two approaches may be combined, by deriving
MemBitmap and ActiveXBitmap from Bitmap, and pass the
according Allocator to the base class. This is how
streams work with streambufs.


A third approach is to provide an allocator as template
argument:

class MemAllocator { ... };
class ActiveXAllocator { ... };

template<class Allocator> class Bitmap
{
  // ...
private:
  Allocator allocator;
};

This third approach can be combined with the second one,
by giving both the allocator type as template argument and
the allocator object as constructor argument. This is how
the STL handles allocators.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Barry Margolin <barmar@genuity.net>
Date: 2000/06/18
Raw View
In article <zaY5KhAsipS5Ewby@robinton.demon.co.uk>,
Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
>In article <394a5536.29331042@news.columbia.edu>, Leonid Portnoy
><lp178@columbia.edu> writes
>>Any thoughts?
>
>Yes, I think your view is fundamentally flawed. Exactly what is going to
>deal with the base class after the derived class has been destroyed? The
>whole point of C++ inheritance is that the derived object constructor is
>responsible for the base class construction, nothing else knows of the
>base class instance and so nothing else can destroy it. The derived
>instance owns the base instance and has no way of passing that ownership
>on. If you do not want that then you must not use any form of
>inheritance.

I think this response is a bit harsh.  In most other aspects of C++
inheritance, the derived class's member function must explicitly invoke the
base class's corresponding member function if passing on is desired.
Construction and destruction are the only places where C++ automatically
invokes base class member functions.  Is there a fundamental reason why
they couldn't have been designed to require explicit passing-on like
ordinary member functions do, or was it just a design choice made by
Stroustrup et al?  I'm not saying that it was the wrong choice (personally,
my favorite OO language is CLOS, which makes it easy to automate passing-on
of *all* method calls), but that doesn't mean that an alternate choice
would be "fundamentally flawed".

--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/06/18
Raw View
In article <jJy25.118$4p1.2205@burlma1-snr2>, Barry Margolin
<barmar@genuity.net> writes
>I'm not saying that it was the wrong choice (personally,
>my favorite OO language is CLOS, which makes it easy to automate passing-on
>of *all* method calls), but that doesn't mean that an alternate choice
>would be "fundamentally flawed".

Sorry, what I meant was that the way the OP wanted to design his
hierarchy was 'fundamentally flawed' because in the context of the way
that C++ is designed you cannot get inheritance to do what he wants. In
addition, I find it difficult to see how ctors and dtors could do
anything different from the way they are currently designed to work
without making radical changes to the entire language. AFAIK the
mechanism is shared by the overwhelming majority of languages that
support inheritance.

Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: comeau@panix.com (Greg Comeau)
Date: 2000/06/20
Raw View
In article <jJy25.118$4p1.2205@burlma1-snr2>,
Barry Margolin  <barmar@genuity.net> wrote:
>Construction and destruction are the only places where C++ automatically
>invokes base class member functions.  Is there a fundamental reason why
>they couldn't have been designed to require explicit passing-on like
>ordinary member functions do, or was it just a design choice made by
>Stroustrup et al?

It was a design choice, that was a fundamental reason, which was
what you said: the automation.  Ctors and dtors are special,
and their semantics are a "conspiracy" between you and the compiler,
hence requiring some integrity of behavior to be maintained,
through exceptions, etc, whereas some of your other functions
are "just" from you.

- Greg
--
Comeau Computing / Comeau C/C++ 4.2.42 (4.2.44 expected soon)
TRY Comeau C++ ONLINE at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/06/20
Raw View
In article <8ih5f2$8k1$1@panix2.panix.com>, Greg Comeau
<comeau@panix.com> writes
>It was a design choice, that was a fundamental reason, which was
>what you said: the automation.  Ctors and dtors are special,
>and their semantics are a "conspiracy" between you and the compiler,
>hence requiring some integrity of behavior to be maintained,
>through exceptions, etc, whereas some of your other functions
>are "just" from you.

But it isn't really that different from the way that the ctors for
objects passed by value are called on entry to the scope and the dtors
are called on exit from that scope.


Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: lp178@columbia.edu (Leonid Portnoy)
Date: 2000/06/17
Raw View
Hi,

    What is the reason C++ automatically calls the destructor for the
base class after calling the destructor for the derived class?

    Sometimes this is not needed, and can even be harmful. For
example, I have a Bitmap class, that does operations on graphical
data. It has an internal pointer to the graphics : 'void *data' as a
member variable, which gets initialized (memory allocated for it) upon
construction, and deallocated in the destructor.

    Now, I wanted to write a DirectX bitmap class, which would perform
the same graphical operations on data, except that the data would be
stored in memory provided by DirectX. So it made sense to derive from
the Bitmap class, and in the constructor obtain a pointer from DirectX
API, and set 'data' to it.

     However, now when I destroy this derived class, I  want to
release the memory (again by using directX api), and to return. But
instead, after this C++ calls the base class's destructor, which
attempts to free the data as if it was regular memory. Obviously this
causes problems.

     Of course, I can set data=NULL, set flags, etc.. to prevent the
base class's destructor from doing damage, but this seems like an
inelegant solution.

     This raises another question : Why does a class have only one
destructor, but multiple constructors? Why not have multiple
destructors, that will be called based on what constructor was used to
create the object.

If there could be many destructors, I would specify, in my base Bitmap
class, a second destructor which would not attempt to free memory.
Let's say it would be called if constructor #2 of the base class was
used to create the object. This constructor would not allocate any
memory but just initialize other members.

Then in the derived class's constructor, I would specify how to create
the base class (by calling constr. #2), and then when destroying my
derived class it would automatically call the appropriate destructor
(the one that doesn't free memory) of the base class...

Any thoughts?
       Leonid Portnoy

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/06/17
Raw View
lp178@columbia.edu (Leonid Portnoy) writes:
>     What is the reason C++ automatically calls the destructor for the
> base class after calling the destructor for the derived class?

Because the whole object is being destroyed. The derived class destructor
cleans up in the derived part of the object, and the base class destructor
cleans up in the base part of the object.

>      Of course, I can set data=NULL, set flags, etc.. to prevent the
> base class's destructor from doing damage, but this seems like an
> inelegant solution.

If the designer of the base class did not have in mind that it could
be extended in the way you would like, then you may be out of luck.

>      This raises another question : Why does a class have only one
> destructor, but multiple constructors?

Because objects are created by intention, with expressions that
supply arguments that can be used to select a constructor. They
are destroyed without any such information, such as by going out
of scope, so there is only one destructor. You are perfectly free
to write multiple overloaded "destroy" functions and call them
yourself as needed.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/06/17
Raw View

Leonid Portnoy schrieb:
>=20
> Hi,
>=20
>     What is the reason C++ automatically calls the destructor for the
> base class after calling the destructor for the derived class?
>=20
>     Sometimes this is not needed, and can even be harmful.

in 99.9999% of all cases it is harmful if a base class destructor is NOT
called automatically.  this is one of the most important features of oo
languages in general and c++ in particular.

>      However, now when I destroy this derived class, I  want to
> release the memory (again by using directX api), and to return. But
> instead, after this C++ calls the base class's destructor, which
> attempts to free the data as if it was regular memory. Obviously this
> causes problems.

yes, but your problems started with the constructor: if the base class
is responsible for allocation then it is responsible for deallocation,
too.  if it just stores the pointer but relies on derived classes to
properly initialize the memory, then it should neither allocate it nor
free it.  this is symmetrical.

>      Of course, I can set data=3DNULL, set flags, etc.. to prevent the
> base class's destructor from doing damage, but this seems like an
> inelegant solution.

no, i do not think so.

did you think that there might be a design problem?  you might have to
separate memory mangement of your bitmap from the functionality.  this
is the solution that seems to me the most straightforward.  you'd then
could have an abstract base class with methods for access to he memory;
you'd then derive a class for each memory model you choose and then you
created another class that uses you abstract base class as interface and
contained the algorithms.  or you would have an abstract base class with
all the algorihtms and abstract methods for memory management.  then you
would derive two classes - one for each memory model.  or you would
choose the approach stl containers that are parametrized by an allocator
class or...

>      This raises another question : Why does a class have only one
> destructor, but multiple constructors? Why not have multiple
> destructors, that will be called based on what constructor was used to
> create the object.

this is not normally necessary because the process of resource
deallocation is always the same.  if you have to distinguish these then
you can remember the way of construction yourself and treat it
appropriately.

and: how would you guarantee, that the number of destructors matches the
number of constructors?  what, if they are different?

regards

 robert

--=20
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra=DFe 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: comeau@panix.com (Greg Comeau)
Date: 2000/06/17
Raw View
In article <t7aegl1s9q.fsf@calumny.jyacc.com>,
Hyman Rosen  <hymie@prolifics.com> wrote:
>lp178@columbia.edu (Leonid Portnoy) writes:
>>      This raises another question : Why does a class have only one
>> destructor, but multiple constructors?
>
>Because objects are created by intention, with expressions that
>supply arguments that can be used to select a constructor. They
>are destroyed without any such information, such as by going out
>of scope, so there is only one destructor. You are perfectly free
>to write multiple overloaded "destroy" functions and call them
>yourself as needed.

I'm not clear this is what you just said, but it's worth pointing out
that destruction is not quite the reverse of construction, despite
so many people being told it is.  That is to say, yes, while
ctors turn raw memory into something useful and dtors turn those
useful thing back ("reverse") to raw memory, what's also important
to note is that you need to consider the life of the object.
Once the object is "alive", what happened at construction time
may or may not be important anymore, therefore, have a matching
dtor may or may not be important anymore.  This sort of begs that
if it has multiple ctors then it should be a requirement that there
be multiple versions of every member function, not just dtors....
which does not necessarily follow... clearly it may in certain cases,
but apparently they were not deemed common/significant enough, and
when they are, you do somethign such as what Hyman suggests.

- Greg
--
Comeau Computing, Producers of Comeau C/C++ 4.2.42 (4.2.43 BETA starting)
Try Comeau C++ online at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Ken Hagan" <K.Hagan@thermoteknix.co.uk>
Date: 2000/06/17
Raw View
"Leonid Portnoy" <lp178@columbia.edu> wrote in message
news:394a5536.29331042@news.columbia.edu...
>
> Hi,
>
>     What is the reason C++ automatically calls the destructor for the
> base class after calling the destructor for the derived class?

The derived class cannot always access all the members of the base
class, so only the base class can clean up reliably. Therefore, the
base class destructor must be called.

It must be called after the derived class destructor since otherwise
the derived class couldn't safely use any part of the base class, which
might make writing the derived class destructor impossible.

>     Sometimes this is not needed, and can even be harmful. For
> example, I have a Bitmap class, that does operations on graphical
> data. It has an internal pointer to the graphics : 'void *data' as a
> member variable, which gets initialized (memory allocated for it) upon
> construction, and deallocated in the destructor.
>
>     Now, I wanted to write a DirectX bitmap class, which would perform
> the same graphical operations on data, except that the data would be
> stored in memory provided by DirectX. So it made sense to derive from
> the Bitmap class, and in the constructor obtain a pointer from DirectX
> API, and set 'data' to it.

You've quietly changed the usage of this "void* data" member. In
effect, the derived class is now lying to the base class. The
derived class should expect to have to work a little harder to
avoid getting caught out.

>      However, now when I destroy this derived class, I  want to
> release the memory (again by using directX api), and to return. But
> instead, after this C++ calls the base class's destructor, which
> attempts to free the data as if it was regular memory. Obviously this
> causes problems.

Speaking as a close personal friend of the base class, I have no
sympathy. How was it supposed to know? Anyway, moving on...

>      Of course, I can set data=NULL, set flags, etc.. to prevent the
> base class's destructor from doing damage, but this seems like an
> inelegant solution.

An inelegant solution? It costs only one line of code in the derived
class destructor. Seems fair to me. The inelegance is borrowing the
data member in the first place and placing an undeletable pointer in
it. You simply aren't playing fair with your base class.

>      This raises another question : Why does a class have only one
> destructor, but multiple constructors? Why not have multiple
> destructors, that will be called based on what constructor was used to
> create the object.

Whilst technically feasible, I'm not sure this really helps,
because...

> If there could be many destructors, I would specify, in my base Bitmap
> class, a second destructor which would not attempt to free memory.
> Let's say it would be called if constructor #2 of the base class was
> used to create the object. This constructor would not allocate any
> memory but just initialize other members.
>
> Then in the derived class's constructor, I would specify how to create
> the base class (by calling constr. #2), and then when destroying my
> derived class it would automatically call the appropriate destructor
> (the one that doesn't free memory) of the base class...

The second constructor and destructor are only needed if someone
goes on to write the derived class. I have no objection to writing
a class with a view to deriving certain related classes from it, but
if I do this too much, I lose encapsulation. (The needs of the
derived classes are now driving the design of the base class.)

> Any thoughts?

Several.

1  Setting data=NULL in the derived class destructor is a much
   simpler solution in this case.
2  When a derived class has to change the usage pattern of a base
   class variable, you should expect to have to play these games.
3  In general, base and derived classes should be more independent
   of one another. Then it is no longer a problem that they are
   constructed and destroyed independently.

More philosophically...

The job of all constructors is to bring the object into existence.
There will be as many constructors as there are kinds of initial
data. Construction is a many-to-one transformation.

Once in existence, objects of the same class are in some sense
equivalent. They may differ in state, but they ought to behave
much like each other. Therefore, it is reasonable to expect
that a single destructor is capable of taking any object of that
class out of existence. Destruction is a one-to-none transformation.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]