tiemann@YAHI.STANFORD.EDU (Michael Tiemann) (05/04/89)
Path: mit-eddie!ll-xn!ames!ncar!boulder!stan!garya From: garya@solbourne.com (Gary Aitken) Newsgroups: comp.lang.c++ Date: 3 May 89 22:39:31 GMT Organization: Solbourne Computer Inc., Longmont, Co. Lines: 51 Apparently-To: lang-c++-netnews-dist@wheaties.ai.mit.edu OK, everyone has been real helpful and with a few patches and fixes we've managed to figure out what g++ and cfront are doing with address of virtual function references. But the whole problem is even worse than I originally mentioned... Consider a function dispatch(objp,fnp) which has very little knowledge of its arguments. It knows the following: objp is a pointer to a C++ object fnp is a pointer to a member function for objp (possibly virtual) In particular, dispatch has no knowledge of the base class for objp. So objp is a void*? If so, I think this is a flawed use of void*. I don't see any reason why objp's type should be so lost that no base class is known. But even if this is so, things can still be made to work. None of the methods/syntax discussed so far will allow dispatch to call fnp on behalf of objp. The code generated by cfront assumes knowledge of where the virtual table is located based on the base class type; the virtual table offset is not in a constant place. You are looking at old versions of g++ and cfront. The 2.0 spec shows how to implement pointers to member functions which are robust enough to solve this problem. A pointer to member function is no longer just a function address or an index into the elusive vtable. Rather, it is a triple, occupying 64 bits, which contains enough information (in worst case) to: 1. Find the `base' of objp 2. Find the appropriate vtable within objp 3. Provide the correct index into the found vtable to perform a virtual function call as though all the information were available. depending on the values of the various elements in the triple. I can see one resolution to this problem: Have cfront force the virtual table to always be at offset 0, so (objp->*fnp)() can be made to always work. The paper by Lippman and Stroustrup on implementing pointers to member functions (in the Denver '88 USENIX C++ Technical Conference Proceedings) is one of many places which shows why this is not a good idea. The solution we currently use (mentioned previously) is a mod to cfront which allows fnp = &objp->f to return the actual address of the member function, and use a C call (*fnp)(objp) Unfortunately, this won't work in some even more esoteric cases, such as when the object has a member which is the address of a member function of itself or another object, and the function involved is virtual. Besides, the above fix relies on knowledge of the implementation (this is passed by cfront as 1st arg). Right. And there are several other reasons why this will not work in the presence of multiple inheritance. Anybody have other thoughts or answers for something that works today? This is a major hangup for us, since we have user applications inserting objects and callback functions in a dispatch table. Your problems should find solutions when C++ 2.0 compilers become available, from AT&T in about 2 months, and from GNU in about one. -- Gary Aitken Solbourne Computer Inc. ARPA: garya@Solbourne.COM Longmont, CO UUCP: ...!{boulder,sun}!stan!garya Michael