Thread: Pointer-to-member functions

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    42

    Pointer-to-member functions

    I am currently playing around with pointer to member functions but am currently having trouble getting them to work with inheritance. Is it possible to define a member function which takes a pointer to another member function which can exist only in a derived version of the class?

    This is my current code:
    Code:
    #include <iostream>
    
    using namespace std;
    
    class basecls
    {
            public:
            typedef void (basecls::* fPtr) (float);
    
            void call (fPtr mPtr)
            {
                    (this->*mPtr)(10);
            }
    
            void foo (float x)
            {
                    cout << x << endl;
            }
    };
    
    class derivcls : public basecls
    {
            public:
            void bar (float x)
            {
                    cout << x * 2 << endl;
            }
    };
    
    int main ()
    {
            derivcls b;
    
            b.call(&derivcls::bar);
    
            return 0;
    }
    It does not compile as call expects a pointer to one of basecls's member functions. However it is possible to do something functionally equiv to this?

    Regards, Freddie.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I suppose you could use a dynamic cast. It should work since derivcls is derived from the base. Not sure, though.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    No virtuals, no dynamic_cast.

    I don't think this is possible. It's not type-safe.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You can do this if you make the function static rather than a normal member function - which in turn means that the "this" pointer would have to be passed along explicitly.

    However, one I sort of question the purpose of the whole construction - it sounds like what you are doing is really some sort of virtual function replacement - perhaps the right thing would be to use proper inheritance and virtual functions instead?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Apr 2005
    Posts
    42
    However, one I sort of question the purpose of the whole construction - it sounds like what you are doing is really some sort of virtual function replacement - perhaps the right thing would be to use proper inheritance and virtual functions instead?
    I guess it is best if I explain my design and see if I can come up with a better API. I am currently porting a Python class over to C++. The Python class makes heavy use of introspection.

    The way the class works is that one inherits from the parent class (basecls) and then defines their own methods. At runtime the init function of the parent class fetches the method list dynamically and calls each of the methods at a suitable time.

    (The class I am porting is part of the application Spark, which is a nice easy to user parser/generator library in Python. The methods are tokenisers which are called when a specific pattern is matched.)

    Since Python is scripted the methods can be defined like so:
    Code:
        def t_whitespace(self, s):
            r" [ \t\r\n]+ "
            self.rv.append(Token('whitespace', ' '))
    The methods are discovered at runtime, the regexp at the top of the method automatically compiled and if/when it matches the method is called.

    In order to port this to C++ I came up with the idea of having a virtual init function, which would register a regexp along with a callback, and then if/when the regexp matches the callback would be called. Although it meant that the methods have to be manually registered it seemed quite nice.

    However, since this seems not to be possible can anyone think of any other clean way of registering tokenisers with the class, along with a way of calling a method when they are matched.

    Regards, Freddie.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It really seems it doesn't work. Only a plain old C-style cast works, but that's unsafe unless you really know what you're doing.
    The best way to make this work in by using virtual functions, simply. How you'd do it in this, I don't know.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    How about making the regex classes separate with a method of determining if it is applicable and for tokenizing? Then make a collections of those objects a member of current basecls.

    I may be totally off here, because this field is unknown to me, but it seems that basecls and derivedcls are not in a IS-A relationship.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> I don't think this is possible. It's not type-safe.
    I *think* the original code can be fixed with just a static_cast<>. I'm having a hard time finding explicit evidence in the standard.

    Right now, my only evidence is that Comeau compiles it without complaining
    I'll keep looking....

    This is actually how MFC does message map callbacks (not that that means it's correct).

    gg

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    But that's under the assumption that the derived type is correct.

    Hmm ... which it probably is, given the scenario. Yeah, might work that way. Of course, that forces the base class to know about the derived class, which is ... less than ideal.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    But a static cast is almost the same as a C-style cast in this case, is it not? Though I would definitely deem it safe enough to use in this approach. It is, after all, a function in a derived class of which the pointer is to the base class.
    I haven't tested, but in theory, it all sounds correct.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Found it....
    Quote Originally Posted by C++ Standard, Section 5.2.9 Static cast, paragraph 9
    An rvalue of type “pointer to member of D of type cv1 T” can be converted to an rvalue of type “pointer to member of B of type cv2 T”, where B is a base class (clause 10) of D, if a valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists (4.11), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.63) The null member pointer value (4.11) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5. ]
    gg

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I don't see why a dynamic cast would actually work with something like this. Apparently it is forbidden, but it would make more sense to cast between pointers with polymorphic types. That's what dynamic cast is for, after all AFAIK.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Apr 2005
    Posts
    42
    Quote Originally Posted by Codeplug View Post
    Found it....
    gg
    If I am understanding your quoted statement correctly then it is indeed possible and applicable. How would you suggest that I integrate the static cast into my above example (so to make using it as seamless as possible)?

    Regards, Freddie.

  14. #14
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    b.call(static_cast<basecls::fPtr>(&derivcls::bar));
    Perhaps.

    I still find function objects more natural than function pointers, but of course there might be the virtual mechanism overhead.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    One of the nice things about member function pointers is that they "behave normally" for virtual member function pointers. In other words, all the polymorphic stuff works the same through member function pointers.

    Here's an easy way to put the burden of casting inside the basecls:
    Code:
        template <typename T>
        void callT( void (T::*mem_fun)(float) )
        {
            call(static_cast<fPtr>(mem_fun));
        }
    Remember that you must use static_cast<> so that any attempt to cast unrelated member function pointers will cause a compile error.

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 04-22-2008, 12:07 PM
  2. Replies: 2
    Last Post: 04-19-2008, 12:06 AM
  3. Ban pointers or references on classes?
    By Elysia in forum C++ Programming
    Replies: 89
    Last Post: 10-30-2007, 03:20 AM
  4. pointers
    By InvariantLoop in forum C Programming
    Replies: 13
    Last Post: 02-04-2005, 09:32 AM
  5. trouble defining member functions
    By dP munky in forum C++ Programming
    Replies: 7
    Last Post: 04-13-2003, 08:52 PM