繁体   English   中英

为什么我不能将指向Derived类成员函数的指针强制转换为类Base?

[英]why can't I cast a pointer to Derived class member function to the same but of class Base?

对我来说,将void(Derived::*)()转换为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();
}

但编译器抱怨a.any_method=&Derived::a_method; 这是一个阻止细微编程错误的障碍,还是一些让编译器编写者生活更轻松的东西? 是否存在变通方法让Base类具有指向Derived成员函数的指针而没有类型知识 (也就是说,我不能使Base成为模板参数Derived模板)。

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

相反的转换是有道理的,这个没有。

不,这有潜在危险。

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

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

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

您需要使用std::function<void()> 这可以是任何类的任何成员,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();
}

在这里你可以看到any_method的实际实现完全是从struct Base抽象出来的,我可以提供一个完成任何事情的函数对象 - 包括方便地调用Derived方法。

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

对于两种类型之间的自动转换,应该保持以下关系:第一种类型的任何实例都应该在第二种类型中表示。

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

现在,当指向成员函数的指针时,关系实际上是相反的。 很明显,任何Base方法都存在于Derived的实例中,但反之则不然。 毕竟,导出的全部内容是更频繁地添加新功能。

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

void Base@call_it(Base& self);

void Derived@a_method(Derived& self);

现在,如果我有两个Derived类型的实例d和类型为Base b ,那么:

  • Base@call_it(d)是有道理的
  • Derived@a_method(b)是编译错误

后者可以是Derived@a_method(dynamic_cast<Derived&>(b)) ,但这会引入运行时检查以实际验证属性。 静态地说它不是可判定的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM