Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!hplabs!nsc!voder!decvax!roger From: roger@decvax.UUCP (Roger H. Scott) Newsgroups: comp.lang.c++ Subject: Re: pointers to member functions Message-ID: <67@espol.decvax.UUCP> Date: 13 Jan 90 07:19:38 GMT References: <967@sl10c.concurrent.co.uk> Reply-To: roger@procase.UUCP (Roger H. Scott) Organization: proCASE Corporation, Santa Clara, CA Lines: 82 In article <967@sl10c.concurrent.co.uk> asc@concurrent.co.uk (Andrew Chittenden,ADT) writes: >However, I do have a problem with the answers - see below. > >> >// However, how is one meant to achieve the >> >// above effect under v2 (pass an arbitrary function of a derived class >> >// with matching parameters)? >> >> 1. Declare any/all such functions to be virtual functions in the base class. >> This is the "right" way. > >I am using these functions as part of an exception handling mechanism. >I've also ideas for using them as part of an event driven scheduler >where each step in a cycle is defined by a function on a class with the >same parameters - it seems a shame that I must define all possible >functions on the base class where the actual functions to be despatched >are on the derived class ( a disc scheduler would be separate from a >terminal scheduler). There must surely be another way. If the derived class functions all take that same parameters (and return the same type) then the solution to your problem is to create a virtual function in the base class (with some generic name) and redefine it in each derived class. A poorly understood fact about pointers-to-member-functions is that a pointer to a *virtual* member function is really like a "message" in a language like SmallTalk - when "called" it will invoke the implementation suitable to the object *on which it is called*, regardless of which class was named when its address was taken. E.g., struct base { virtual void f(); }; typedef void (base::baseMF)(); struct derived : public base { void f(); // redefine }; void dispatch(base *p, baseMF *mf) { (p->*mf)(); } void foo() { base b; derived d; dispatch(&b, &base::f); // invokes base::f() dispatch(&d, &base::f); // invokes derived::f() dispatch(&d, &derived::f); // ERROR - I lost my battle w/ AT&T on this // one - my claim was that &derived::f is a // synonym for &base::f - AT&T disagrees } I should add that in my experience 9 out of 10 uses of pointers-to-member- functions are needless. Their perceived need is usually the result of poor design of some other aspect of a system - they can often be eliminated by making the right member functions virtual in the right places. >> 2. Cast. Have you ever seen a cast involving a pointer-to-member-function >> *without* a typedef? This is the "wrong" way. I suspect people have mis-read this semi-editorial semi-rhetorical comment. My point was that noone wants to read f(p, q, (a *(b::*)())&c::d); rather than typedef a *(b::bMF)(); ... f(p, q, (bMF *)&c::d); which is bad enough in itself. > >Why is this the "wrong" way? I have tried casting but it does not >work. Casting is a crock - it is an admission that you and your programming language don't see eye-to-eye and negotiations have broken down. It is very unfortunate that Bjarne's book gives the strong impression that "void *"s and casts are the stock-and-trade of C++ programming. When you say you have tried casting and "it does not work", what do you mean? Did your code not compile? If so, either it is syntactically incorrect [not unlikely unless you are using typedefs, and even then ...] and/or your C++ translator is flawed [known to be true for 1.2 cfront from AT&T, likely elsewhere]. If this is the case use typedefs, check carefully, and try again. Did your code compile but execute "incorrectly" (i.e. - not as you expected)? I would have to see your code to tell you what is wrong in this case.