[comp.lang.c++] Wrapping inheritance hierarchies

zarmer@hplabsz.HPL.HP.COM (Craig Zarmer) (09/15/89)

I have a question about the proper use of inheritance in C++ 2.0.  I'm
using InterViews, a C++ class library for building user interfaces,
but I think my question extends to any use of an aquired class
hierarchy.  I'm trying to 'wrap' the window class hierarchy in
InterViews to add some extra functionality.  Though in the case of
InterViews I have source and could just hack the root class, I'd
prefer not too, and in the general case we usually don't get source.

As an example, take the following InterViews classes:

class Interactor {public virtual void Draw(); ...};
class PushButton : public Interactor {...};
class ScrollBar : public Interactor {...};

In my own world I have

class ApplicObject {...};

I want to add a public member
  ApplicObject *subject
to all Interactors.  I then need a type or types that will allow me to
generically access subject and any public member of Interactor.

Schemes that don't work at all:

1) Add a new class SubjectView that contains an ApplicObject* and
make Interactor inherit from it.  This would only work if I had InterViews
source, which I'm pretending I don't.  

2) Create a subclass of every interesting Interactor and add
subject.  This leaves me with no generic way to reference subject.

3) Create a class SubjectView, and create subclasses of every
interesting Interactor by inheriting both from the Interactor subclass
and SubjectView.  I.e.

class SubjectView {public: ApplicObject *subject;};
class MyPushButton : public PushButton, public SubjectView {...};

This gives me generic access to both InterViews and subject, but not
at the same time.  There is no way to coerce from SubjectView* to
Interactor*, and I need to be able to Draw() and access subject.

4) Create SubjectView as above, then create a dummy class inheriting
from SubjectView and Interactor to get a common type, then create
subclasses inheriting from the common type and InterViews subclasses:

class SubjectView {public: ApplicObject *subject;};
class SubjectInteractor : public SubjectView, public Interactor {};
class MyPushButton : public PushButton, public SubjectInteractor {};

This is real close, but MyPushButton will get 2 Interactors.  Since I
don't have source, I can't make Interview's PushButton inherit
virtually from Interactor.


Ugly schemes that sort-of work:

5) Define SubjectView:

class SubjectView { 
public:
  ApplicObject *subject;
  Interactor *view;
...};

Make subclasses of Interactor classes that inherit from SubjectView
too and in their constructors, have them set view to themselves.  In
other words, give Mom a pointer to Dad via the Child.

6) Forget inheritance; make SubjectView a wholy separate class.  Use a
hash table to get the relation from Interactors to SubjectViews.


Since most companies that develop libraries for sale will not release
source, this scenario seems rather common.  Is there a proper way to
take in a class library and wrap all of the classes with some extra
functionality? 

Thanks,
Craig Zarmer
zarmer@hplabs.hp.com

vaughan@mcc.com (Paul Vaughan) (09/16/89)

   From: zarmer@hplabsz.HPL.HP.COM (Craig Zarmer)

   I have a question about the proper use of inheritance in C++ 2.0.  I'm
   using InterViews, a C++ class library for building user interfaces,
   but I think my question extends to any use of an aquired class
   hierarchy.  I'm trying to 'wrap' the window class hierarchy in
   InterViews to add some extra functionality.  Though in the case of
   InterViews I have source and could just hack the root class, I'd
   prefer not too, and in the general case we usually don't get source.

   As an example, take the following InterViews classes:

   class Interactor {public virtual void Draw(); ...};
   class PushButton : public Interactor {...};
   class ScrollBar : public Interactor {...};

   In my own world I have

   class ApplicObject {...};

   I want to add a public member
     ApplicObject *subject
   to all Interactors.  I then need a type or types that will allow me to
   generically access subject and any public member of Interactor.

   Schemes that don't work at all:

   1) Add a new class SubjectView that contains an ApplicObject* and
   make Interactor inherit from it.  This would only work if I had InterViews
   source, which I'm pretending I don't.  

   2) Create a subclass of every interesting Interactor and add
   subject.  This leaves me with no generic way to reference subject.

   3) Create a class SubjectView, and create subclasses of every
   interesting Interactor by inheriting both from the Interactor subclass
   and SubjectView.  I.e.

   class SubjectView {public: ApplicObject *subject;};
   class MyPushButton : public PushButton, public SubjectView {...};

   This gives me generic access to both InterViews and subject, but not
   at the same time.  There is no way to coerce from SubjectView* to
   Interactor*, and I need to be able to Draw() and access subject.

   4) Create SubjectView as above, then create a dummy class inheriting
   from SubjectView and Interactor to get a common type, then create
   subclasses inheriting from the common type and InterViews subclasses:

   class SubjectView {public: ApplicObject *subject;};
   class SubjectInteractor : public SubjectView, public Interactor {};
   class MyPushButton : public PushButton, public SubjectInteractor {};

   This is real close, but MyPushButton will get 2 Interactors.  Since I
   don't have source, I can't make Interview's PushButton inherit
   virtually from Interactor.


   Ugly schemes that sort-of work:

   5) Define SubjectView:

   class SubjectView { 
   public:
     ApplicObject *subject;
     Interactor *view;
   ...};

   Make subclasses of Interactor classes that inherit from SubjectView
   too and in their constructors, have them set view to themselves.  In
   other words, give Mom a pointer to Dad via the Child.

   6) Forget inheritance; make SubjectView a wholy separate class.  Use a
   hash table to get the relation from Interactors to SubjectViews.


   Since most companies that develop libraries for sale will not release
   source, this scenario seems rather common.  Is there a proper way to
   take in a class library and wrap all of the classes with some extra
   functionality? 

	You ask a very good question.  I've been beating my head
against the wall trying to figure this one out for awhile.  So far my
answer has been: avoid having it come up.  Since we are actually
making the libraries that I'm worried about, we can just make base
classes virtual in anticipation of the problem later on.  I really
wish you could have both a virtual and nonvirtual derivation from a
base class in the inheritance hierarchy and have the virtual one use
the nonvirtual one, instead of creating a new one.
	But in response to your question, I have a partially
satisfactory answer, based on your choice #3.  "But how do you access
methods from both base classes," you say?  Answer: cheat, kludge, lie,
steal.  Actually it's not THAT bad--check out the following code.  It
compiles and runs with g++ 1.35.1.  The basic technique is to use
pointers or references of both base class types (that is, one of each
base class type).  These pointers point at the same object, and
therefore that object must derive from both base classes.  The trick
is that when the assignment is made, the actual type of the object is
known and the legality of the assignments is assured.  Later, the
actual class is not known, but you can access either base class
methods through the appropriate pointer.  "But, suppose your program
is structured so that you don't have access to the actual type when
you want to make such an assignment," you say.  Well, I haven't
covered that yet.  I'm still working on it.  If you don't find
yourself saying that because you don't think it can happen that way,
let me know.  Also, I suspect you can improve on some of the
properties of this technique.

#include <stream.h>

class LibBase {
public:
  LibBase() { cout << "LibBase Constructor\n";};
  foo() {};
};

class LibDerived : public LibBase {
public:
  LibDerived() { cout << "LibDerived Constructor\n";};
};


class MyBase {
public:
  MyBase() { cout << "MyBase Constructor\n";};
  bar() {};
};

class MyDerived : public MyBase, public LibDerived {
public:
  MyDerived() { cout << "MyDerived Constructor\n"; };
};

class Client {
public:
  Client(LibBase* lbp, MyBase* mbp) 
    { cout << "Client Constructor\n"; lb = lbp; mb = mbp;};
  LibBase* lb;  // duplicate pointers, one for each base class
  MyBase* mb;
  foobar() { lb->foo(); mb->bar();};
};


main() {
  MyDerived md;
  MyBase& mb = md;  //duplicate references, one of each base class
  LibBase& lb = md;

  lb.foo();
  mb.bar();

  Client c(&md,&md);
  c.foobar();
}



 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

jima@hplsla.HP.COM (Jim Adcock) (09/20/89)

Interesting issue.  A user of a derived class D decides that D really 
should have had a virtual base class B instead a non-virtual B.  

How does a user decide that without seeing the source?  How can a user 
be sure that D doesn't change the operation of B?

--This is far different from a class E whose base B is declared virtual. Which 
represents a contract by E not to use B in a way that would preclude the 
base instance "B-part" of E from being used by another class. E would 
typically only do things to the B-part in the E's constructors and destructors.
Thus E uses B by mere aggregation with B -- B's capabilities are not mixed with
E's, but rather B's and E's capabilities are orthogonal.  In which case B's and
E's capabilities should be implemented totally separately: implement the meat
of E instead in a class Eprime, and then create E via trivial derivation:

class E : public B, public Eprime
{
  E() : B(something), Eprime(somethingelse) {}
  ~E() {maybesomething();}
};

Then, if the user of your classes decides he/she needs something like E
but with a virtual B, the user can trivially make such a class:

class Evirt : public virtual B, public E
{
  Evirt() : B(something), Eprime(somethingelse) {}
  ~Evirt() {maybesomething();}
};

Or you could provide both flavors, virtual base "Evirt" and non-virtual base 
"E" to your users to use as they please.

But you complain: "I write my Eprime-meat as part of E because my Eprime-part
is not really orthogonal to B."  Fine, but then the user was never in
a situation where having B virtual would have done the user any good.  
Because E was never written in a way to let the B part be shared by another 
class.