A bit like polymorphism, but with function pointers

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.
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
Why do you need to attempt something like that?
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)();
}
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.
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?
> 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
That's what I'm talking about. Thanks!
Topic archived. No new replies allowed.