Topic: Some features to be added to class-based OO languages (continued)


Author: o.v@k.ro (O.V.)
Date: Wed, 19 Mar 2003 19:55:19 +0000 (UTC)
Raw View
This was meant as an addition to the thread

http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF-8&threadm=59143289.0301280527.1e95174d%40posting.google.com&rnum=1&prev=/groups%3Fdq%3D%26hl%3Den%26lr%3D%26ie%3DUTF-8%26selm%3D59143289.0301280527.1e95174d%2540posting.google.com

called "Some features to be added to class-based OO languages", in
this group, which I started in January; but it seems I cannot add any
more messages to it, probably because the last message contained is
too old. Any references to previous postings mean those in that
thread.
In the meantime I've been able to think of a more practical example,
in case anyone is still interested; even if it is not as relevant for
combining classes dynamically as the one with the tax payer classes in
my first posting.
Sorry for bringing the subject up again, but I strongly felt that the
thread is not complete without a practical example.


Say I have a library for a set of viewers of images in various file
formats (TIFF, JPEG, PNG etc.). The library consists of a basic class
Viewer that exposes the common general functionality of the viewers,
and of several derived classes that implement the actual viewers.
These are all objects of window type, so Viewer derives from TWindow,
from which it inherits the standard behaviour of answering to common
Windows events such as create, show, resize or close. It has some
additional methods which are common to all viewers, such as setting
the file to be viewed and getting the file extension(s) for the
supported format(s).
The base class just declares these methods as pure virtual ones, their
implementation is left to the viewer classes. Besides, these all
redefine the Paint (HDC) method of TWindow, so that it does the actual
drawing of the image. Additionally, they may define other methods of
their own that are not in the base class.
Now, this is what the library contains. Say I want to add some
Photoshop-like image processing functionality to these classes, such
as setting the brightness or make the green color component more
intense. The simplest way to do this for an individual viewer class
would be to redefine the Paint (HDC) method, such that after the
painting is done, a bitmap of the needed dimensions and resolution is
obtained, then changed according to the processing and drawn in the
device context.
The issue is how do I do this simply for all viewer classes. With dyn.
inheritance, I would define a class EnhancedViewer that dynamically
derives from a Viewer interface, redefine the Paint method in it, then
build the actual enhanced viewer objects dynamically from a base
object of the desired viewer class with EnhancedViewer on top.
Alternatively, I can define the EnhancedViewer as a class that
normally derives from Viewer directly, then build every individual
enhanced viewer dynamically as an EnhancedViewer over an object of the
desired viewer class, by the mechanism indicated in point 1.3.
"Dynamic class inheritance" of my initial posting.

Of course, the pertinent objection is that this all can be done by
writing EnhancedViewer as a template class which derives from its
argument class, then instantiating it with individual viewer classes.
It can, and generally pretty much of dyn. inheritance can be solved
this way. This solution has, however, some weak points:
- every class combination that is to be used at any program point must
be declared explicitly. Say for instance that in a program there are
more classes that enhance the viewer classes above, such as one that
puts a watermark over the image (therefore it must always be topmost),
and others like it. Then to define a WatermarkViewer over an
EnhancedViewer over another 2 or 3 enhancements over an individual
viewer, one would have to explicitly write its type as

  WatermarkViewer<EnhancedViewer<Enh2Viewer<...<IndividualViewer>...>>>

of course not necessarily in one step, but this is what must be
achieved in the end. This makes the use of such combinations much less
flexible. For instance, the type of viewer that is to be used in a
function may have to be determined dynamically from a set of possible
combinations, which is definitely more difficult with templates;
surely, it can be done. The possible combinations could conceivably be
very many; if there were 10 independent possible enhancements, there
would be 10! enhancement combinations over every individual viewer
class. Also, all classes that may participate in a combination in any
program must be known at compile time, which makes it impossible to
have combinations with dynamically obtained objects like in COM. Also,
any separately compiled module can have only combinations of classes
known in that module. All these are limitations in the program's
flexibility and maintainability.
- the classes that may participate in combinations, which means
principially all classes, must be written as templated classes, which
is somewhat more difficult; in fact, I suspect that if this would be
done on a large scale the complications would be substantial,
considering also that there may be other class templates to be written
for various reasons
- every templated combination is an overhead in compile time and
program size

This is why IMO the dyn. inheritance solution is definitely better.

O.V.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]