繁体   English   中英

C ++:强制转换成员函数指针

[英]C++: Casting Member Function Pointer

在以下程序中,如何将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/include/openssl/ssl.h#1173-我正在尝试使结构ssl_private_key_method_st的不同实例在不同的私钥上运行。 我试图让另一个结构从ssl_private_key_method_st继承,并让sign / decrypt / complete方法对继承的结构的实例变量进行操作。

我知道使用SSL_ [sg] et_ex_data间接将数据传递给这些函数,但是我一直在寻找一种尽可能简单/直接的方式将实例数据传递给这些函数。

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

TypeFoobar是不同类型的函数指针(分别为int (*)(int)int (NB::B::*)(int) )。 虽然可以将一个强制转换为另一个强制,但使用结果调用该函数将导致未定义的行为。

8.2.10重新解释演员表[expr.reinterpret.cast]
...
6 可以将函数指针显式转换为其他类型的函数指针。 [注意: 通过指向与函数定义中使用的类型不同的函数类型(11.3.5)的指针调用函数的效果是不确定的。 — [end note]除了将“ pointer to T1”类型的prvalue转换为“ pointer to T2”类型(其中T1T2是函数类型)并返回其原始类型会产生原始指针值,这种处理的结果指针转换未指定。 [注意:有关指针转换的更多详细信息,请参见7.11。 —尾注]

简短的答案:你不知道。

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

您应该考虑使用std::function<int(int)>而不是int (*)(int) 这将允许您存储类似以下lambda的内容:

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

此lambda通过引用捕获当前对象,并且此引用存储在std::function对象本身内部。 但是,您也可以直接或通过lambda或bind表达式将任何其他函数分配给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;
}

指针到成员函数不能像常规指针那样工作。 它保存了函数在类布局中的“相对地址”。因此请使用静态声明函数。 喜欢:

static int bar(int i) 
{
// code here
}

暂无
暂无

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

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