[try Beta version]
Not logged in

 
A bit like polymorphism, but with function pointers

Apr 26, 2015 at 2:45pm
Hi. I'm trying to figure out why can't I do this:
1
2
3
4
5
6
7
8
9
10
class base{};
class derived:public base{
    public: void func(){};
};
typedef void(base::*p_f)();
int main(){
    derived a;
    p_f f=&derived::func;
    (a.*f)();
};


That would throw an error at compile claiming it can't convert <pointer to derived member> to <pointer to base member>, even though derived is a child of base. Is there a different way of creating a generic "pointer to member of derivations of <class>" type?
Thanks.
Apr 26, 2015 at 3:02pm
I don't think it would be safe to allow that. Imagine the derived class having some data member that it manipulated in the function and then you were able to call that function on a base class object that didn't have that data member, what would happen?
Last edited on Apr 26, 2015 at 3:02pm
Apr 26, 2015 at 3:03pm
Why do you need to attempt something like that?
Apr 26, 2015 at 3:09pm
Note that the opposite, <pointer to base member> to <pointer to derived member>, is perfectly fine.
1
2
3
4
5
6
7
8
9
10
class base{
    public: void func(){};
};
class derived:public base{};
typedef void(derived::*p_f)();
int main(){
    derived a;
    p_f f=&base::func;
    (a.*f)();
}
Apr 26, 2015 at 3:34pm
I don't think it would be safe to allow that. Imagine the derived class having some data member that it manipulated in the function and then you were able to call that function on a base class object that didn't have that data member, what would happen?
Why do you need to attempt something like that?

That makes sense. I didn't think about the base class because in my particular case, it is pure abstract.

I'm trying to make a modular program, that would be able to execute structurally identical functions from an arbitrary number of modules (native or not).
You may think of it as a plugin system: it scans for available libraries, then collects the functions and stores them in a map for later use.
I don't worry about security because it's pretty much for personal and educational use.

Of course, I *could* add a wrapper for every single function, but that would be a nuisance.
Apr 26, 2015 at 3:40pm
I've seen Qt to offer a "plugin system": http://doc.qt.io/qt-5/plugins-howto.html
Does that give you any new ideas?
Apr 26, 2015 at 4:39pm
> I *could* add a wrapper for every single function, but that would be a nuisance.

The standard library has a polymorphic call wrapper (compared to which the Qt plugin system looks like some thing that the cat brought in during the night).
http://en.cppreference.com/w/cpp/utility/functional/function

Forward, bind and wrap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <functional>
#include <string>
#include <map>
#include <utility>
#include <memory>

struct function_map
{
    using function_type = std::function< void() > ;

    template < typename FN, typename... ARGS >

    bool insert( std::string key, FN&& fn, ARGS&&... args )
    { return function_map.emplace( std::move(key), std::bind( std::forward<FN>(fn), std::forward<ARGS>(args)... ) ).second ; }

    bool call( const std::string& key )
    {
        const auto iter = function_map.find(key) ;
        if( iter != function_map.end()  ) { iter->second() ; return true ; }
        else return false ;
    }

    private: std::map< std::string, function_type > function_map ;
};

double non_member_fun( int a, double b, short c )
{ std::cout << "non_member_fun( " << a << ", " << b << ", " << c << " )\n" ; return a+b+c ; }


int main()
{
    struct A { void foo( int a ) { std::cout << "main::A::foo( " << this << ", " << a << " )\n" ; } };
    struct B { void bar( int a, char b ) { std::cout << "main::B::bar( " << this << ", " << a << ", " << b << " )\n" ; } };
    const auto closure = [] { std::cout << "main::closure()\n" ; return 9 ; };

    A a ; std::cout << "std::addressof(a): " << std::addressof(a) << '\n' ;
    B b ; std::cout << "std::addressof(b): " << std::addressof(b) << "\n\n" ;

    function_map fmap ;
    fmap.insert( "one", &A::foo, a, 123 ) ; // pass a by value
    fmap.insert( "two", &B::bar, std::ref(b), 456, 'B' ) ; // pass b by wrapped reference
    fmap.insert( "three", closure ) ;
    fmap.insert( "four", non_member_fun, 789, 12.34, 56 ) ;

    for( std::string key : { "two", "four", "three", "one" } )
    {
        std::cout << key << " => " ;
        fmap.call(key) ;
    }

}

http://coliru.stacked-crooked.com/a/058edddd74afffe3
Apr 26, 2015 at 5:14pm
That's what I'm talking about. Thanks!
Topic archived. No new replies allowed.