[MUD-Dev] Spoofs

Daniel.Harman at barclayscapital.com Daniel.Harman at barclayscapital.com
Thu Sep 27 11:19:03 CEST 2001


> From: Brian Hook [mailto:bwh at wksoftware.com]

> The classic illustration is they inadvertently illustrate why C++
> is basically broken -- it ties the interface and implementation to
> each other tightly.  So when B inherits from A, you're never sure
> (from the outside) if it's inheriting the interface (for
> polymorphism) or the implementation (for specialization) or both.

Which is pretty much the problem COM solves. Of course convincing
developers to create versioned interfaces rather than just expand
old ones is something else (at least when you are writing in house
apps and have full deployment control).

> They go on to make an even more interesting assertion: extension
> by aggregation is generally preferable to extension by inheritance
> for the above reason.  They almost seem to actively discourage
> subclassing.  I have to admit that I'm fairly guilty of using
> "is-a" vs. "has-a" a lot more than I should, but I'm slowly
> getting over it.  Hell, I'm using callbacks for a lot of stuff now
> instead of polymorphism because, in the end, it's actually quite a
> bit cleaner than subclassing everything just to minorly extend its
> behaviour.

I've gone off the typical C++ inheritance pattern as it either ends
up bloated, inflexible or messy. I've started to use the same
approach ATL uses in its design whereby templates are used to keep
the code concise and flexible whilst allowing you to insert code
anywhere in the hierarchy.

I had a bit of text here that tried to explain the approach and it
occured to me that I wasn't doing a very good job. Below is an
extract from a fairly good overview explaining the paradigm and a
link for the full (and overly long for this list) document.

8<-------------
Base classes with templates  

If you've been waiting to learn what I mean by "upside-down
inheritance," then wait no longer. Traditionally, when you derive
from a class, everything above your immediate base class is
fixed. This was the key design problem we encountered in Designs #1,
2, and 3 because we lost flexibility every time we introduced a base
class.

ATL solves this problem by allowing the developer to use template
arguments to specify the base class of a base class. The classes I
used as examples in Design #4 are quite similar to the classes in
ATL. Here is what an ATL definition would look like (the list of
base classes to CMyControl has been heavily edited).

  class CMyControl : 
	public CComObjectRootE< 
		CComSingleThreadModel >,
	public CComControl< CMyControl, 
		CWindowImpl< CMyControl, CWindow > >
  {
  };

 

The first template parameter to CComControl is the most derived
class so CComControl can access siblings in the hierarchy. This
works just as it did for AxControlImpl in the last section.

The second template argument is the definition of what CComControl
should use for a base class. This allows you to insert your own
classes into the class hierarchy, thus making ATL extremely flexible
if you need to change its behavior. If you browse your own ATL
project, you may not see this template argument, because ATL
automatically uses the default if it isn't specified.

For example, this list shows the derivation hierarchy of CMyControl,
with the base class at the top and the most derived class at the
bottom:

  CWindow
  CWindowImplRoot<CWindow>
  CWindowImplBaseT<CWindow>
  CWindowImpl<CMyControl, CWindow>
  CComControl<CMyControl, 	
		CWindowImpl<CMyControl, CWindow> >
  CMyControl

 
The two classes in blue are both defined by the template arguments
to CComControl and can therefore be replaced or overridden by the
developer.  For example, you could subclass CWindow and create
CCenteredWindow. You would then change the template argument to
CWindowImpl, and your new class would be inserted into the
hierarchy.

Remember that most functions are not virtual. If you use
CCenteredWindow to override functions in CWindow, then your override
will be called, not because it is virtual, but because it is the
most derived implementation of the function.

The reason I call this upside-down inheritance is that the most
derived class defines the base class and therefore defines the
behavior of the base class. This is the opposite of the typical
case, where the derived classes have little or no control over the
behavior of the base class.

8<-------------

  http://www.devx.com/free/mgznarch/vcdj/1999/julmag99/atlinherit1.asp

If you've seen all this before then its probably not very
interesting, but when I first saw it I was impressed.

Dan
_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://www.kanga.nu/lists/listinfo/mud-dev



More information about the mud-dev-archive mailing list