asc@concurrent.co.uk (Andy Chittenden) (12/01/89)
// We are using pointers to member functions with version 1.2. Below is // cut down example. This compiles fine under version 1.2 but doesn't // under version 2. class base { public: int fn1(int p); }; class derived : public base { public: int fn2(int p); }; typedef int (base::*EH_function) (int); class dispatcher { public: dispatcher(EH_function p); }; main() { dispatcher a(base::fn1); dispatcher b(derived::fn2); // fails to compile under v2 } // I can understand why the second line does not compile (derived::fn2 // is not a function of base). However, how is one meant to achieve the // above effect under v2 (pass an arbitrary function of a derived class // with matching parameters)? Thanks in anticipation, Andy Chittenden
ark@alice.UUCP (Andrew Koenig) (12/02/89)
In article <950@sl10c.concurrent.co.uk>, asc@concurrent.co.uk (Andy Chittenden) writes: [example that declares `dispatcher' as taking a pointer to a member of class `base' > dispatcher a(base::fn1); > dispatcher b(derived::fn2); // fails to compile under v2 > // I can understand why the second line does not compile (derived::fn2 > // is not a function of base). However, how is one meant to achieve the > // above effect under v2 (pass an arbitrary function of a derived class > // with matching parameters)? The `dispatcher' function takes a pointer to a member of class `base.' There may be some members of class `derived' that are not members of class `base,' so you can't pass any member of `derived' to a function that takes a pointer to a member of `base' as its argument. In particular, if fn2 were a member of `base' you would have been able to say dispatcher b(base::fn2); and there would have been no problem. Watch this, though. Every member of class `base' is also a member of class `derived.' Therefore you CAN pass a member of class `base' to a function that expects a pointer to a member of class `derived'! Example: void f(int (derived::*)(int)); main() { f(derived::fn2); // OK f(base::fn1); // also OK! } This may seem backwards at first, but if you think about it for a while you will see that it has to be this way, version 1 to the contrary notwithstanding. This phenomenon is often called `contravariance.' -- --Andrew Koenig ark@europa.att.com
roger@procase.UUCP (Roger H. Scott) (12/07/89)
In article <950@sl10c.concurrent.co.uk> asc@concurrent.co.uk (Andy Chittenden) writes: >... >// 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. 2. Cast. Have you ever seen a cast involving a pointer-to-member-function *without* a typedef? This is the "wrong" way.
fredriks@kuling.UUCP (Fredrik Stax{ng) (12/12/89)
I think the following piece of code would work. In The C++ Language Reference Manual 2.0 sec 5.4 it says: Pointer to member may be explicitly converted ... when the two type are pointers to member functions of classes derived from each other. However my C++ compiler refuses to compile this (error: cast to member). It is HCR C++ ver 2.01. Is this supposed to work? If not, why not? (I know it is unsafe, but it would be very un-C to disallow it because of that.) class Base { public: void Error() ; } ; typedef void (Base::*PMemF)() ; class Derived: public Base { public: void F1() ; } ; main() { PMemF P3 ; P3 = (PMemF)(Derived::F1) ; } Fredrik Stax{ng | C looks like a mix of Algol and TECO. CS Student@Uppsala University | -- KPJ Jaakkola fredriks@kuling.docs.uu.se | - -- Fredrik Stax{ng | C looks like a mix of Algol and TECO. CS Student@Uppsala University | -- KPJ Jaakkola fredriks@kuling.docs.uu.se |
asc@concurrent.co.uk (Andy Chittenden) (12/18/89)
Thanks to both Roger Scott and Andrew Koenig for responding to my query. However, I do have a problem with the answers - see below. roger@procase.UUCP (Roger Scott) replies: > In article <950@sl10c.concurrent.co.uk> asc@concurrent.co.uk (Andy Chittenden) writes: > >... > >// 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. > > 2. Cast. Have you ever seen a cast involving a pointer-to-member-function > *without* a typedef? This is the "wrong" way. Why is this the "wrong" way? I have tried casting but it does not work. Andrew Koenig also replies: > .... > Watch this, though. Every member of class `base' is also a member of > class `derived.' Therefore you CAN pass a member of class `base' > to a function that expects a pointer to a member of class `derived'! > Example: > > void f(int (derived::*)(int)); > > main() > { > f(derived::fn2); // OK > f(base::fn1); // also OK! > } > > This may seem backwards at first, but if you think about it for a while > you will see that it has to be this way, version 1 to the contrary > notwithstanding. I hope you're not seriously suggesting that I declare my typedef for the derived type - this goes against the paradigm. I understand that the above would be valid as every member of base is also a member of derived. > > This phenomenon is often called `contravariance.' I understand why the v2 compiler complains about my example. What I was looking for was a way to use the "feature" that was available in v1.2 of cfront (see my reply to Roger above). One way may be to use non-class based functions - this goes against the general principle of keeping things object-oriented. Andy Chittenden
asc@concurrent.co.uk (Andrew Chittenden,ADT) (01/11/90)
Thanks to both Roger Scott and Andrew Koenig for responding to my query. However, I do have a problem with the answers - see below. roger@procase.UUCP (Roger Scott) replies: > In article <950@sl10c.concurrent.co.uk> asc@concurrent.co.uk (Andy Chittenden) writes: > >... > >// 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. > > 2. Cast. Have you ever seen a cast involving a pointer-to-member-function > *without* a typedef? This is the "wrong" way. Why is this the "wrong" way? I have tried casting but it does not work. Andrew Koenig also replies: > .... > Watch this, though. Every member of class `base' is also a member of > class `derived.' Therefore you CAN pass a member of class `base' > to a function that expects a pointer to a member of class `derived'! > Example: > > void f(int (derived::*)(int)); > > main() > { > f(derived::fn2); // OK > f(base::fn1); // also OK! > } > > This may seem backwards at first, but if you think about it for a while > you will see that it has to be this way, version 1 to the contrary > notwithstanding. I hope you're not seriously suggesting that I declare my typedef for the derived type - this goes against the paradigm. I understand that the above would be valid as every member of base is also a member of derived. > > This phenomenon is often called `contravariance.' I understand why the v2 compiler complains about my example. What I was looking for was a way to use the "feature" that was available in v1.2 of cfront (see my reply to Roger above). One way may be to use non-class based functions - this goes against the general principle of keeping things object-oriented. Apologies for the late response to these replies, but we have been having trouble with our news feed. Andy Chittenden
roger@decvax.UUCP (Roger H. Scott) (01/13/90)
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.
idf@cs.bham.ac.uk (Ian Fitchet <FitchetI>) (12/06/90)
I came across a problem while trying to explain pointers to functions from a C perspective in a C++ tutorial. This failed so I looked it up in a book which said that the following code should be valid. #include <stream.h> class foo { int a; public: foo() { a = 1; } void print() { cout << a << "\n"; } void bar() { a = 3; } }; main() { void (foo::*ptr2bar)() = &foo::bar; foo bletch; cout << "Initially a = " ; bletch.print(); bletch.(*ptr2bar)(); cout << "Finally a = "; bletch.print(); } The Sun C++ compiler (CC -v prints out "Sun C++ 2.0 FCS - 10/20/89") does the following: %cd /mbhome/staff/idf/src/cc/ %CC -o foo q.c %CC q.c: %"q.c", line 36: error: syntax error %1 error %cc -o /mbhome/staff/idf/src/cc/foo -c -I/usr/CC/incl % %Compilation exited abnormally with code 1 at Wed Dec 5 16:03:08 ie a syntax error on the call. g++ version 1.37.2 beta (based on GCC 1.37) does the following: %cd /mbhome/staff/idf/src/cc/ %g++ -o foo q.c %q.c: In function int main (): %q.c:30: parse error before `*' % %Compilation exited abnormally with code 1 at Wed Dec 5 16:32:09 ie gives a parse error on the declaration of ptr2bar void (foo::*ptr2bar)() = &foo::bar; Is it me, or are the compilers to blame? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ian Fitchet | "Have you heard the one about the FitchetI@uk.ac.bham.cs | orangutan and the pomegranate?" FitchetI%cs.bham.ac.uk@nsfnet-relay.ac.uk | - Gerald the Gorilla (NTNO'CN)
ianhogg@cs.umn.edu (Ian J. Hogg) (12/07/90)
In article <1369@christopher-robin.cs.bham.ac.uk> idf@cs.bham.ac.uk (Ian Fitchet <FitchetI>) writes: > > I came across a problem while trying to explain pointers to functions >from a C perspective in a C++ tutorial. This failed so I looked it up >in a book which said that the following code should be valid. > >#include <stream.h> >class foo { > int a; >public: > foo() { a = 1; } > void print() { cout << a << "\n"; } > void bar() { a = 3; } >}; >main() >{ > void (foo::*ptr2bar)() = &foo::bar; > foo bletch; > > cout << "Initially a = " ; > bletch.print(); > bletch.(*ptr2bar)(); ^^^^^^^^^^^^^^^^^^^^^^ (bletch.*ptr2bar)(); > cout << "Finally a = "; > bletch.print(); >} > Compiles and runs fine on HP's cfront 2.0. Lippman's book discusses this on pages 211-212. ============================================================================== Ian Hogg ian@dms.cdc.com
stu4@larry.mcrcim.mcgill.edu (Craig Jones) (01/19/91)
Let me say at the outset, I am new to C++ (but loving it) so please be patient with me if this is a simple question... I am trying to pass a pointer of a function (that is a member of a class) to the ftw() function (taken from <ftw.h>). My class is defined as follows: class fileclass { // some variables here int show_file (char*, struct stat*, int); // the above must be defined like this because of // restrictions in ftw(). public: fileclass (); void show (); ~fileclass (); }; And the functions as: void fileclass::show() { ftw(path, &show_file, 100); } ^^^^^^^^^^^ Not sure what to put here. int fileclass::show_file(char* path, struct stat* status, int depth) { printf("%s\n", path); return 0; } The question is: How do I write the second parameter to the ftw function? Thanks for any time and help.... Craig bnrmtl!stu4@larry.mcrcim.mcgill.edu
garnett@shera..bellcore.com (Michael Garnett) (01/21/91)
In article <1991Jan18.222713.26249@scrumpy@.bnr.ca> bnrmtl!stu4@larry.mcrcim.mcgill.edu writes: >I am trying to pass a pointer of a function (that is a member of a >class) to the ftw() function (taken from <ftw.h>). > You can't pass a member function to ftw to call. ftw does not know about your class, and cannot thus provide the "this" paramater. Methods must be called ON an object, ftw has no such object to call your function on. A pointer to the member function showfile of fileclass is of type: int (fileclass::*)(const char*, stat*, int); This is not the same as regular pointers to functions. Michael
stu4@larry.mcrcim.mcgill.edu (Craig Jones) (01/23/91)
This is in reference to an earlier posting I made asking how to pass pointers of member functions (specifically to ftw()). Here is an example of how to do it (based on many replies to my plea) .... #include <stream.h> #include <ftw.h> // Class Definition class fooclass { public: static int greeting(char*, struct stat*, int); // ^^^^^^ NECESSARY TO BE ABLE TO PASS THIS FUNCTION // TO ftw() void call_ftw (); void call_ftw2(int (*function)(char*, struct stat*, int)); }; void fooclass::call_ftw() { int return_int; return_int = ftw ("..", &fooclass::greeting, 10); } void fooclass::call_ftw2 (int (*function)(char*, struct stat*, int)) // // Calls ftw() and passes a pointer to the function to ftw. // { int return_int; return_int = ftw ("..", function, 10); } int fooclass::greeting(char* path, struct stat* status, int number) { cout << "Now in greeting " << path << "\n"; return 0; } // NON member function definition int nonclass_greeting (char* path, struct stat* status, int number) { cout << "Now in non class greeting " << path << "\n"; return 0; } main() { fooclass fooobj; // Call member function that calls ftw with a pointer to a // member function fooobj.call_ftw(); cout << "\n Now going to do next...\n\n"; // Pass outside function as a pointer to be used inside a class member function fooobj.call_ftw2(nonclass_greeting); } Many thanks for all the help that was given. ----------------------------------------------------------- Craig Jones bnrmtl!stu4@larry.mcrcim.mcgill.edu Bell Northern Research, Montreal. -----------------------------------------------------------
Roy.Browning@p0.f506.n106.z1.fidonet.org (Roy Browning) (01/24/91)
In a message of <Jan 18 22:27>, Craig Jones (1:106/88@fidonet) writes: >void fileclass::show() >{ > ftw(path, &show_file, 100); >} ^^^^^^^^^^^ Not sure what to put here. > >int fileclass::show_file(char* path, struct stat* status, int depth) >{ > printf("%s\n", path); > return 0; >} Craig: I you declare the "show_file" member to be "static" then create a wrapper function along the following format. inline _cdecl int WrapperShow_File(char* path, stat* status, int depth) { return classname::show_file(path, status, depth); } If "show_file" isn't static then you have to call it via a specific instance. inline _cdecl int WrapperShow_File(char* path, stat* status, int depth) { return instancename.show_file(path, status, depth); } Substitute the 'C' wrapper function for the member name in the call to "ftw". This should work per your request. On the learning C++urve, Roy Browning
dgorton@jupiter.newcastle.edu.au (David Mark Gorton) (06/07/91)
In Stroustrups "The C++ Programming Language" pp 153-154 an example is given of how to "fake" the expression of the type of a pointer to a member function. Has this been standardised ? (I dont have access to a copy of the ARM at the moment, though I have one on order.) I am writing a class definition for TCP connections using the Transport Level Interface and have the following class definition class tcp { // TCP connection private : // Data members ... public : ... void ConnectionRelease(void); ... }; The sample program in the Sun Network Programming Guide has a C function connrelease() { ... } and in the server function run_server(...) { signal(SIGPOLL, connrelease); if (ioctl(conn_fd, I_SETSIG, S_INPUT) < 0) ... } I wish to do the equivalent in C++ using ConnectionRelease() from class tcp. The header file for <sys/signal.h> on our SUN 3/80 has typedef void SIG_FUNC_TYP(int); typedef SIG_FUNC_TYP *SIG_TYP; extern "C" { SIG_TYP signal(int, SIG_TYP); ... }; The AT&T C++ Compiler accepts the following // // Fake type of pointer to member - See <signal.h> and "The C++ // Programming Language" - Bjarne Stroustrup, pp 153-154 for details // SIG_TYP pf = SIG_TYP(&tcp::ConnectionRelease); signal(SIGPOLL, pf); if (ioctl(fdConnection, (int) I_SETSIG, (caddr_t) S_INPUT) < 0) Is this correct (and the standard) ?? Thanks in advance, Dave --------------------------------------------------------------------------- Dave Gorton. Department of Computer Science, University of Newcastle, Newcastle, 2308, Australia. .-_|\ Telephone : (049) 216 034 / \ \.--._/ Internet : dgorton@cs.newcastle.edu.au v csdmg@cc.newcastle.edu.au ---------------------------------------------------------------------------
sarima@tdatirv.UUCP (Stanley Friesen) (06/11/91)
In article <dgorton.676272036@jupiter.newcastle.edu.au> dgorton@jupiter.newcastle.edu.au (David Mark Gorton) writes: >In Stroustrups "The C++ Programming Language" pp 153-154 an example is given >of how to "fake" the expression of the type of a pointer to a member function. >Has this been standardised ? Nope. Quite the opposite, it is being thoroughly depreciated. (Indeed it will not work properly with multiple inheritance). It has been replaced in cfront 2.0 and later by a new composite type - the 'pointer to member'. Try to get at least one book about level 2.X c++. Lippman's is the best. Any book covering cfront 2.0 or later will explain pointers to members. [And of course, if your c++ compiler is only a level 1.2 compiler, upgrade it, it is radically incompatible with all current compilers]. -- --------------- uunet!tdatirv!sarima (Stanley Friesen)