Why doesn't C++ have a pointer to member function type?

后端 未结 9 1870
一生所求
一生所求 2020-12-30 07:24

I could be totally wrong here, but as I understand it, C++ doesn\'t really have a native \"pointer to member function\" type. I know you can do tricks with Boost and mem_fu

9条回答
  •  北荒
    北荒 (楼主)
    2020-12-30 08:23

    @RocketMagnet - This is in response to your other question, the one which was labeled a duplicate. I'm answering that question, not this one.

    In general, C++ pointer to member functions can't portably be cast across the class hierarchy. That said you can often get away with it. For instance:

    #include 
    using std::cout;
    class A { public: int x; };
    class B { public: int y; };
    class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
    
    int main() {
        typedef void (A::*pmf_t)();
        C c; c.x = 42; c.y = -1;
    
        pmf_t mf = static_cast(&C::foo);
        (c.*mf)();
    }
    

    Compile this code, and the compiler rightly complains:

    $ cl /EHsc /Zi /nologo pmf.cpp
    pmf.cpp
    pmf.cpp(15) : warning C4407: cast between different pointer to member representations, compiler may generate incorrect code
    
    $
    

    So to answer "why doesn't C++ have a pointer-to-member-function-on-void-class?" is that this imaginary base-class-of-everything has no members, so there's no value you could safely assign to it! "void (C::)()" and "void (void::)()" are mutually incompatible types.

    Now, I bet you're thinking "wait, i've cast member-function-pointers just fine before!" Yes, you may have, using reinterpret_cast and single inheritance. This is in the same category of other reinterpret casts:

    #include 
    using std::cout;
    class A { public: int x; };
    class B { public: int y; };
    class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
    class D { public: int z; };
    
    int main() {
        C c; c.x = 42; c.y = -1;
    
        // this will print -1
        D& d = reinterpret_cast(c);
        cout << "d.z == " << d.z << "\n";
    }
    

    So if void (void::*)() did exist, but there is nothing you could safely/portably assign to it.

    Traditionally, you use functions of signature void (*)(void*) anywhere you'd thing of using void (void::*)(), because while member-function-pointers don't cast well up and down the inheritance heirarchy, void pointers do cast well. Instead:

    #include 
    using std::cout;
    class A { public: int x; };
    class B { public: int y; };
    class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
    
    void do_foo(void* ptrToC){
        C* c = static_cast(ptrToC);
        c->foo();
    }
    
    int main() {
        typedef void (*pf_t)(void*);
        C c; c.x = 42; c.y = -1;
    
        pf_t f = do_foo;
        f(&c);
    }
    

    So to your question. Why doesn't C++ support this sort of casting. Pointer-to-member-function types already have to deal with virtual vs non-virtual base classes, and virtual vs non-virtual member functions, all in the same type, inflating them to 4*sizeof(void*) on some platforms. I think because it would further complicate the implementation of pointer-to-member-function, and raw function pointers already solve this problem so well.

    Like others have commented, C++ gives library writers enough tools to get this done, and then 'normal' programmers like you and me should use those libraries instead of sweating these details.

    EDIT: marked community wiki. Please only edit to include relevant references to the C++ standard, and add in italic. (esp. add references to standard where my understanding was wrong! ^_^ )

提交回复
热议问题