且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么C ++不具有指向成员函数类型的指针?

更新时间:2022-11-01 15:30:31

@RocketMagnet - 这是回应您的其他问题,标记为重复的问题。我正在回答 问题,而不是这个问题。



一般来说,C ++指向成员函数的指针不能移植到类层次结构。这说,你可以经常逃避它。例如:

  #include< iostream> 
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<< \\\
;}};

int main(){
typedef void(A :: * pmf_t)();
C c; c.x = 42; c.y = -1;

pmf_t mf = static_cast< pmf_t>(& C :: foo);
(c。* mf)();
}

编译此代码,编译器正确

  $ cl / EHsc / Zi / nologo pmf.cpp 
pmf.cpp
pmf.cpp (15):警告C4407:在不同的指针之间转换成员表示,编译器可能生成不正确的代码

$

$ b b

所以回答为什么C ++没有一个指向成员函数的on-void-class?是这个想象的基础类的没有成员,所以没有价值,你可以安全地分配给它! void(C :: )()和void(void :: )()是互不兼容的类型。



我打赌你在想等待,我已经成员函数指针之前就好了!是的,你可能有,使用reinterpret_cast和单继承。这是与其他重新解释类型相同的类别:

  #include< iostream> 
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<< \\\
;}};
class D {public:int z; };

int main(){
C c; C.x = 42; c.y = -1;

//这将打印-1
D& d = reinterpret_cast< D&>(c);
cout<< d.z ==< d.z ;
}

所以如果 void(void :: *) )确实存在,但是没有什么可以安全/可移植地分配给它。



传统上,使用签名 void(void :: *)(),因为while成员使用 - 函数指针不能很好地向上和向下继承的继承,void指针做得很好。而是:

  #include< iostream> 
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<< \\\
;}};

void do_foo(void * ptrToC){
C * c = static_cast< C *>(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);
}

为什么C ++不支持这种类型的转换。指针到成员函数类型已经必须处理虚拟或非虚拟基类以及虚拟和非虚拟成员函数,所有类型都在同一类型中,在一些平台上将它们扩展为4 * sizeof(void *)。我认为,因为它会进一步复杂的指针成员函数的实现,原始函数指针已经解决这个问题很好。



像其他人一样,C ++为库编写者提供了足够的工具来完成这项工作,然后像你和我一样的正常程序员应该使用这些库而不是冒出这些细节。



编辑:标记社区wiki。请仅编辑以包含对C ++标准的相关引用,并添加斜体。 (特别是添加标准的参考,我的理解是错误的!^ _ ^)


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_fun etc. But why did the designers of C++ decide not to have a 64-bit pointer containing a pointer to the function and a pointer to the object, for example?

What I mean specifically is a pointer to a member function of a particular object of unknown type. I.E. something you can use for a callback. This would be a type which contains two values. The first value being a pointer to the function, and the second value being a pointer to the specific instance of the object.

What I do not mean is a pointer to a general member function of a class. E.G.

int (Fred::*)(char,float)

It would have been so useful and made my life easier.

Hugo

@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 <iostream>
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<pmf_t>(&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 <iostream>
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<D&>(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 <iostream>
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<C*>(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! ^_^ )