[comp.sys.mac.programmer] Multiple Inheritance for HandleObjects in C++

bowman@reed.UUCP (Eric Bowman) (06/29/90)

I've just discovered, to my horror, that you can't create HandleObjects
with multiple base classes in MPW C++.  Are there any work arounds for this?
Anyone know why this is the case?

Thanks,
bobo
bowman@reed.{bitnet,UUCP,edu}

Personal to Alex Chaffee -- my email bounces.  Any other addresses?

lsr@Apple.COM (Larry Rosenstein) (06/29/90)

In article <15132@reed.UUCP> bowman@reed.UUCP (Eric Bowman) writes:
>I've just discovered, to my horror, that you can't create HandleObjects
>with multiple base classes in MPW C++.  Are there any work arounds for this?
>Anyone know why this is the case?

The reason is that the standard implementation of C++ multiple inheritance
requires that you pass a pointer to the middle of an object's storage.
That's because each class' method is compiled to access fields using fixed
offsets.  (If you look at the generated C code for a native C++ class, you
will see that it adds an offset to the object pointer before calling a
method.)

Methods of HandleObject subclasses expect to be passed a handle,
and it's not possible to pass a handle that refers to the middle of an
object.  Plus you have to worry about the handle moving if the heap
compacts.  

One workaround is to inherit from a primary class, and delegate some
functions to to instances of the secondary classes.  In other words, instead
of inheriting from A & B, you inherit only from A, and keep an instance of B
around.  Methods that need to access B's functionality do so by sending a
message to the instance of B.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

amanda@mermaid.intercon.com (Amanda Walker) (06/30/90)

In article <15132@reed.UUCP>, bowman@reed.UUCP (Eric Bowman) writes:
> I've just discovered, to my horror, that you can't create HandleObjects
> with multiple base classes in MPW C++.  Are there any work arounds for this?
> Anyone know why this is the case?

The short answer is that HandleObjects, which were designed to allow
compatibility with Object Pascal, are incapable of representing objects with
multiple parent classes.  The memory representation and method dispatching
strategies in Object Pascal were only designed with single inheritance in
mind.

The longer answer is that C++ multiple inheritance depends on the ability
to treat a pointer to a piece of an object as an object in its own right.
This can be done with normal C "structs," but not with Macintosh handles.

The only workaround I know of is to put a HandleObject into an instance
variable of a "conventional" C++ object, with method wrappers to connect
the two inheritance chains.  This is kind of grody, and it still doesn't
let you inherit from, say, several MacApp classes, but it's better than
nothing...

--
Amanda Walker
InterCon Systems Corporation
--

lsr@Apple.COM (Larry Rosenstein) (06/30/90)

In article <268BA8DC.4CD4@intercon.com> amanda@mermaid.intercon.com (Amanda Walker) writes:
>
>The short answer is that HandleObjects, which were designed to allow
>compatibility with Object Pascal, are incapable of representing objects with

The PascalObject class provides compatibility with Object Pascal.

HandleObjects are separate from PascalObjects.  They are essentially native
C++ objects with the restrictions that multiple inheritance isn't allowed
and the objects must be allocated on the heap.  (Since multiple inheritance
isn't allowed, they probably use the older & more efficient C++ runtime
implementation.)

There's also the class SingleObject, which also uses the older
implementation, and therefore doesn't support multiple inheritance.
SingleObjects are allocated on the heap as non-relocatable pointers and can
be allocated on the stack.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

chewy@apple.com (Paul Snively) (06/30/90)

In article <15132@reed.UUCP> bowman@reed.UUCP (Eric Bowman) writes:
> I've just discovered, to my horror, that you can't create HandleObjects
> with multiple base classes in MPW C++.  Are there any work arounds for 
this?
> Anyone know why this is the case?

Larry Rosenstein and Amanda Walker have already done an excellent job of 
answering the question Eric poses, but I'd like to point out something 
else:

Since Eric is using HandleObjects, he apparently isn't concerned about 
Object Pascal compatibility.  This means that he's probably concerned 
about fragmenting the heap, which standard C++ objects, being based on 
malloc and free, tend to do.

Andy Shebanow, a former engineer here in MacDTS, wrote a very good article 
in "D e v e l o p" describing a class that he created called "PtrObject."  
The idea was to provide all of the functionality of standard C++ but to 
use NewPtr and DisposPtr to manage memory instead of malloc and free.  
Perhaps Eric would benefit from using Andy's PrtObject class.

Just a thought...

__________________________________________________________________________
                                Paul Snively
                      Macintosh Developer Technical Support
                             Apple Computer, Inc.

chewy@apple.com

Just because I work for Apple Computer, Inc. doesn't mean that I believe 
what they believe, or vice-versa.
__________________________________________________________________________

amanda@mermaid.intercon.com (Amanda Walker) (06/30/90)

In article <8937@goofy.Apple.COM>, lsr@Apple.COM (Larry Rosenstein) writes:
> HandleObjects are separate from PascalObjects.

Oops, you're right.  However, as we both seem to have noted simultaneously,
both PascalObjects and HandleObjects have the same restriction to single
inheritance.

--
Amanda Walker
InterCon Systems Corporation
--

steve@hite386.UUCP (Steve Hite) (07/02/90)

amanda@mermaid.intercon.com (Amanda Walker) writes:

>In article <15132@reed.UUCP>, bowman@reed.UUCP (Eric Bowman) writes:
>> I've just discovered, to my horror, that you can't create HandleObjects
>> with multiple base classes in MPW C++.  Are there any work arounds for this?
>> Anyone know why this is the case?

>The only workaround I know of is to put a HandleObject into an instance
>variable of a "conventional" C++ object, with method wrappers to connect
>the two inheritance chains.  This is kind of grody, and it still doesn't
>let you inherit from, say, several MacApp classes, but it's better than
>nothing...

>--
>Amanda Walker
>InterCon Systems Corporation
>--


Larry Rosenstein writes:

>One workaround is to inherit from a primary class, and delegate some
>functions to to instances of the secondary classes.  In other words, instead
>of inheriting from A & B, you inherit only from A, and keep an instance of B
>around.  Methods that need to access B's functionality do so by sending a
>message to the instance of B.


Eric,
  
  Amanda and Larry were kind enough to post a response to the same question
I had a couple of months ago.  The difference in the replies to you suggest
to me that they have come up with workarounds to the problem since their
discussion with me (or they already knew and forgot to mention them :-)).  

  I bow to their experience with MacIntosh programming and I would like to
suggest some additions to these.  I suggest you read T.A. Cargill's
article in the 1990 Usenix C++ Conference Proceedings entitled "Does C++
Really Need Multiple Inheritance?" starting on page 315.  

T.A. Cargill's conclusion paragraph states:

"In the majority of published examples, multiple inheritance in C++ is not 
required to express programs.  In most cases a single inheritance solution 
is simpler - inheritance from a class being replaced by the embedding of an 
object.  In light of this we should view multiple inheritance in C++ as a 
large scale research project, in which we must evaluate its usefulness and 
weigh it's costs.  The results to date suggest that multiple inheritance is 
not paying its way."  
  

Also, Grady Booch states in "Object Oriented Design w/Applications" on pp
110-111:

The Meaning of Multiple Inheritance Relationships Among Classes

"...The need for multiple inheritance in object oriented programming languages
is still a topic of great debate.  In our experience, we find multiple in-
heritance to be like a parachute: you don't always need it, but when you do,
you're really happy to have it on hand..."

  I believe Larry and T.A. Cargill are saying the same thing.  Amanda
is losing me at the point "...method wrappers to connect the two inheritance
chains".  I would need to see an example of this because I'm shooting blanks
trying to visualize it.  

  From what I've read, I don't consider their approach (Larry and T.A.) a 
"kluge" to get around a machine-dependent feature such as HandleObject.  
Rather, it's a different way of looking at the problem from a design 
standpoint.  If you still believe that you have relationships that *must* be 
implemented with MI then I would answer that there is not a well thought-out 
way yet of programming this in C++ on the MacIntosh without fragmenting the 
heap.  Definitely get Grady Booch's new book I just mentioned and the three 
C++ Usenix volumes that are a very good reference for exploratory experiences 
and findings in C++ implementations.
 

-------------------------------------
Steve Hite
...gatech!uflorida!unf7!hite386!steve

amanda@mermaid.intercon.com (Amanda Walker) (07/03/90)

In article <37@hite386.UUCP>, steve@hite386.UUCP (Steve Hite) writes:
> Amanda
> is losing me at the point "...method wrappers to connect the two inheritance
> chains".  I would need to see an example of this because I'm shooting blanks
> trying to visualize it.  

Sorry about that :-).  I guess I forgot to translate my thoughts into
English before I typed them in.  What I was suggesting is the same thing
Larry did: having a C++ object (let's call it "a") with HandleObjects as
instance variables (let's call them "b" and "c").  My phrase "method wrapper"
means that "a" has methods that invoke the corresponding method from "b" or
"c".  Since "a" is not actually a subclass of either "b" or "c", you have
to manually pass the methods along, instead of having it done automatically
by the inheritance tree built by the compiler & linker.

It's clumsier that "real" multiple inheritance, but it might be enough for
many applications...

--
Amanda Walker
InterCon Systems Corporation
--
"I can only assume this is not the first-class compartment."
	--Hitchhiker's Guide to the Galaxy

beard@ux5.lbl.gov (Patrick C Beard) (07/16/90)

Here is how I use Handles and C++ objects together without fragmenting
heaps.  This allows full C++ style objects with single and multiple
inheritance.  

// overloaded storage operators.  Allows floating C++ objects.
void* operator new(size_t size) 
{
  Handle h = NewHandleClear((long)size);
  if(!h || MemError() != noErr)
	return nil;
  MoveHHi(h);
  return (void*)*h;
}

operator delete(void* p)
{
  if(p) {
    Handle h = RecoverHandle((Ptr)p);
    DisposHandle(h);
  }
}


Using these storage operators, create an object like so:

MyClass **h_instance, *p_instance;

p_instance = new MyClass;
h_instance = RecoverHandle((Ptr)p_instance);

Now, you can refer to the object henceforth using h_instance, which you
can cast to a handle and perform standard locking and unlocking before
and after use.  For example:

(**h_instance).MyMethod(); //  be sure to lock if necessary!

--
-------------------------------------------------------------------------------
-  Patrick Beard, Macintosh Programmer                        (beard@lbl.gov) -
-  Berkeley Systems, Inc.  ".......<dead air>.......Good day!" - Paul Harvey  -
-------------------------------------------------------------------------------