C :铸造成员功能指针

C++: Casting Member Function Pointer

本文关键字:功能 指针 成员      更新时间:2023-10-16

在以下程序中,如何将bar键入foo?

#include <iostream>
namespace NA {
    class A {
    public:
        int (*foo)(int);
    };
}
namespace NB {
    class B : public NA::A {
    public:
        int bar(int i) {
            std::cout << i << std::endl;
            return i*2;
        }
        B() {
            this->foo = bar;  // how to type cast this fn pointer?
        }
    };
}

int main() {
    NA::A *a = new NB::B(); 
    std::cout << a->foo(2) << std::endl;
}

我尝试了如下打字,但是当我运行程序时会出现严重错误:

B() {
    typedef int (*TypeFoo)(int);
    this->foo = reinterpret_cast<TypeFoo> (&bar);
}

这是我运行时的结果:

$ ./a.out 
31947824
63895648

我期待2和4。

更新:在看到回答表明没有解决上述问题的解决方案之后,我将通过我试图解决的具体问题进一步更新此问题。

请参阅https://boringssl.googlesource.com/boringssl//head/head/include/include/openssl/ssl.h#1173-我试图拥有struct struct ssl_private_keykey_method_method_st _ST em> ssl_private_private_private_private在不同的私钥上操作。我试图让另一个struct从 ssl_private_key_method_st 中继承,并具有 sign/decrypt/complete 方法在继承struct的实例变量上运行。

我知道使用 ssl_ [sg] et_ex_data 间接地将数据传递到这些函数,但是我正在寻找一种更简单/直接的方法,将实例数据传递到这些函数时。<<<<<<<<<<<<<<<<<<<<<<<<<<<</p>

您正在遇到未定义的行为。

TypeFoobar是不同类型的功能指针(分别为int (*)(int)int (NB::B::*)(int)(。 虽然可以将一个施放给另一个,但使用结果调用该函数将导致不确定的行为。

8.2.10 retinterpret cast [expr.reinterpret.cast]
...
6.可以将功能指针明确转换为其他类型的功能指针。[注意:通过指针调用功能类型(11.3.5(的函数的效果与函数定义中使用的类型不同。 - end Note Note]除了将"指针"类型的PRVALUE转换为" To To To To to T2"的类型(其中T1T2是函数类型(,然后返回其原始类型产生原始指针值,此类指针转换的结果未指定。。[注意:另请参见7.11。 指针转换的详细信息。 - 末尾注]

简短答案:您不。

非静态成员功能指针很奇怪。调用一个涉及一个秘密this参数,它们可能是virtual。这使它们无法与普通功能指针混合。

您应该考虑使用std::function<int(int)>而不是int (*)(int)。这将使您可以存储以下lambda之类的东西:

B(){
    std::function<int(int)> myfn = [this](int x){
        return bar(x);
    };
}

此lambda通过参考捕获当前对象,此引用存储在std::function对象本身内。但是,您可以直接或通过lambda或绑定表达式将任何其他功能分配给std::function

另一方面,如果您的bar方法实际上并不取决于实例,则只需将其制作static即可。这将允许它与常规功能指针混合,因为它不再需要秘密this,并且不能为virtual

static int bar(int i) {
    std::cout << i << std::endl;
    return i*2;
}

这样写,可以将&B::bar分配给常规int (*)(int)功能指针。

您的TypeFoo定义了指向常规功能的指针,而bar是一种方法。每个非静态方法都有一个隐式的第一个参数this

因此,您应该确定您需要什么:常规功能(在这种情况下是bar静态(或一种方法,在这种情况下,您应该这样打字:

typedef int (B::*TypeFoo)(int);

reinterpret_cast是一个易于实践的练习。如果您不能没有它 - 代码不正确的可能性很高。

调用成员函数指针是真正的痛苦。我建议您采用以下方式进行此操作,简化了许多上下文处理:

#include <iostream>
namespace NA {
    class A {
    public:
        int (A::*foo)(int);
    };
}
namespace NB {
    class B : public NA::A {
    public:
        int bar(int i) {
            std::cout << i << std::endl;
            return i*2;
        }
        int callFoo(int x) {
            return (this->*foo)(x);
        }
        B() {
            this->foo = (int(A::*)(int)) (&B::bar);
        }
    };
}

int main() {
    NA::A *a = new NB::B(); 
    std::cout << ((NB::B*)a)->callFoo(2) << std::endl;
}