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

时间:2019-05-21 04:08:05

标签: c++ casting

在以下程序中,如何将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 将数据间接传递给这些函数,但我一直在寻找一种更简单/直接的方式,将实例数据传递给这些函数。< / p>

5 个答案:

答案 0 :(得分:2)

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

TypeFoobar是不同类型的函数指针(分别为int (*)(int)int (NB::B::*)(int))。  虽然可以相互转换,但使用结果调用函数将导致不确定的行为。

  

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

答案 1 :(得分:2)

简短的回答:您不会。

非静态成员函数指针很奇怪。调用其中一个涉及一个秘密的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或bind表达式将任何其他函数分配给std::function

另一方面,如果您的bar方法实际上并不依赖实例,则只需使其为static。这将使其与常规函数指针混合使用,因为它不再需要秘密的this,而不再是virtual

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

这样写,&B::bar可以分配给常规的int (*)(int)函数指针。

答案 2 :(得分:1)

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

因此,您应该确定自己需要什么:常规函数(在这种情况下,将bar设为静态)或方法,在这种情况下,您应该像这样键入:

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

reinterpret_cast是容易出错的做法。如果没有它就无法进行转换-您的代码很可能不正确。

答案 3 :(得分:0)

调用成员函数指针确实很痛苦。我建议您按照以下方式进行操作,简化许多上下文处理:

#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;
}

答案 4 :(得分:-1)

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

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