C++ 为什么可以';我是否将指向派生类成员函数的指针强制转换为相同但属于类基的?

C++ 为什么可以';我是否将指向派生类成员函数的指针强制转换为相同但属于类基的?,c++,member-function-pointers,C++,Member Function Pointers,在我看来,将void(派生::*)()强制转换为void(Base::*)()非常安全,如下代码: #include <iostream> #include <typeinfo> using namespace std; struct Base{ void(Base::*any_method)(); void call_it(){ (this->*any_method)(); } }; struct Derived: publ

在我看来,将
void(派生::*)()
强制转换为
void(Base::*)()
非常安全,如下代码:

#include <iostream>
#include <typeinfo>
using namespace std;
struct Base{
    void(Base::*any_method)();
    void call_it(){
        (this->*any_method)();
    }
};
struct Derived: public Base{
    void a_method(){
        cout<<"method!"<<endl;
    }
};
int main(){
    Base& a=*new Derived;
    a.any_method=&Derived::a_method;
    a.call_it();
}
#包括
#包括
使用名称空间std;
结构基{
无效(基::*任何_方法)();
void call_it(){
(此->*任何方法)();
}
};
结构派生:公共基{
作废a_方法(){

cout如果您的
Derived::a_method()
尝试使用仅存在于
Derived
中而不存在于
Base
中的数据成员,并且您在
Base
对象(或从
Base
派生但与
派生
无关的对象)上调用它,会发生什么


另一种方式的转换是有意义的,这一种没有意义。

不,它有潜在的危险

派生类函数可以使用
*this
的所有派生类属性。可以在任何基类实例上调用指向基类函数的指针,即使不是派生类型的实例也是如此

访问非派生类的实例的派生类属性是行不通的,因此不允许将指向派生类函数的指针强制转换为指向基类指针的指针


另一方面,将指向基类函数的指针强制转换为指向派生类函数的指针是安全合法的。

您需要使用
std::function
。它可以是任何类的任何成员、lambda、自由函数、函数对象,无论您需要什么,都非常方便

#include <iostream>
#include <typeinfo>
using namespace std;
struct Base{
    std::function<void()> any_method;
    void call_it(){
        any_method();
    }
};
struct Derived: public Base{
    void a_method(){
        cout<<"method!"<<endl;
    }
};
int main(){
    Derived* d = new Derived;
    Base& a= *d;
    a.any_method = [d] { d->a_method(); };
    a.call_it();
}
#包括
#包括
使用名称空间std;
结构基{
std::函数任意_方法;
void call_it(){
任意_方法();
}
};
结构派生:公共基{
作废a_方法(){

我想这可能有点令人惊讶。但是如果你仔细想想,这是有道理的

要使两种类型之间的强制转换自动进行,以下关系应保持不变:第一种类型的任何实例都应可在第二种类型中表示

例如,如果
d
Derived
的实例,那么它可以自动转换为
Base&
,因为
Derived
的任何实例也是
Base
的实例。这是继承

现在,当涉及到指向成员函数的指针时,这种关系实际上是相反的。对于
派生的
实例,显然存在
Base
的任何方法,但情况并非相反。毕竟,派生的全部目的是更频繁地添加新功能

另一种可视化的方法是使用自由函数。
这只是常规函数中的一个隐式参数,如果我们将其显式化,我们会得到:

void Base@call_it(Base& self);

void Derived@a_method(Derived& self);
现在,如果我有两个
d
类型的
Derived
b
类型的
Base
实例,那么:

  • Base@call_it(d) 
    有意义
  • Derived@a_method(b) 
    是一个编译错误

后者可以是
Derived@a_method(动态_-cast(b))
,但这引入了运行时检查来实际验证属性。静态上它是不可判定的。

现在还不清楚
std::function
在这方面有什么帮助:
std::function
也有同样的问题,如果一个人放弃给
任何方法
成员函数的类型,那么就没有必要使用
std::函数
而不是普通的自由函数指针。对吗?@Lorenzo:No.
std::function
。函数可以存储它自己的
这个
指针。此外,函数指针上总是有一个指向
std::function
的点-有状态lambdas,例如
std::bind
的结果。我编辑了answ呃,让我们更清楚地看到,
std::function
是如何即时解决这个问题的。