Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!bloom-beacon!apple!claris!hearn From: hearn@claris.com (Bob Hearn) Newsgroups: comp.lang.c++ Subject: Re: Smalltalk-80 like inheritance in C++ possible ? Message-ID: <9174@claris.com> Date: 24 Mar 89 17:10:34 GMT References: <110@honold.UUCP> <5481@rlvd.UUCP> <1411@sw1e.UUCP> Reply-To: hearn@claris.com (Bob Hearn) Organization: Claris Corporation, Mountain View CA Lines: 53 In article <1411@sw1e.UUCP> uucibg@sw1e.UUCP (Brian Gilstrap [5-3929]) writes: >The biggie is of course the fact that C++ uses strong typing of objects (e.g. >determine at compile time what function/method is to be invoked ) while >Smalltalk and Smalltalk-like languages use weak typing of objects and actually >accomplish function address resolution at run-time. The net result of this is Well, yes, but you *do* have virtual functions in C++, which give you most of the functionality you want. The prototypical example is the graphic object class that has a virtual draw function that is redefined for each derived class, so you can have a ptr to a graphic object without knowing what specific type it is, tell it to draw, and have the correct function be called (determine at run time). This example is actually quite applicable to what I am doing: writing an object-oriented graphics package in C++. One problem I found with virtual functions was this: I wanted to have a graphic object class, and I wanted to have a graphics database class which would store graphic objects in a list and know how to manipulate them. One of the things the graphics database should do is take a ptr to a function and apply it to every object in the database. Well, one problem right off is that sometimes the func. should take the object as a parameter, but often it would be convenient to use a graphic object member function, so the object would be an implicit parameter, and the parameterization would be different. OK, no problem there, just overload the traversal member func (the one that applies the function). But this is a problem: suppose the graphics database is supposed to be packaged up as a utility to be used by a lot of different clients, each of whom may want their objects to do different things. The natural thing to do is derive new object classes off of the original graphic object class. But wait -- now I want to use a member function of this derived object class to pass to the database's traverse function, so it can be applied to all the objects. But, since the database was written without knowledge of the derived class, I can't know in advance the type of the function parameter to the traverse functions, specifically, the class it is a member function of (this won't make sense to those of you who don't have member function ptrs in your C++; they're an extension). At first, I gave up and just decreed that if you want to do this sort of thing, you must create a flat function as an interface from the traverse function to your new class, and pass that instead of the member function. But this is an extra level of indirection, and nothing can be inline here. Well, eventually I found a hack to make it work: turns out that, at run time, the only thing that distinguishes one member function ptr from another is whether or not it's virtual. If the base object class has no virtual functions, then when you apply a member func. ptr to objects of that class it assumes the ptr is to a 'real' function; it doesn't check to see if it's virtual. But of the base class *does* have virtual functions, it checks to see whether the member func ptr is real or virtual. If it's virtual, it looks up the function in the object's class, which can be determined at run time, because members of classes with virtual functions all have ptrs to their class's virtual function table. So, if I cast the ptr to member function of derived class to a ptr to member function of base class, where the base class has virtual functions, then it works! Ta da. Aren't you glad you read this all the way to the end? :-) Bob Hearn hearn@claris.com