0

In the following program, How do I typecast bar to 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;
}

I tried typecasting as follows but something is going terribly wrong when I run the program:

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

Here's the result when I run:

$ ./a.out 
31947824
63895648

I was expecting 2 and 4. How does one typecast the member function pointers above?

Update: After seeing responses indicating there's no solution to the above problem, I am updating this question further with the specific problem I was trying to address.

Please see https://boringssl.googlesource.com/boringssl/+/HEAD/include/openssl/ssl.h#1173 -- I am trying to have different instances of the struct ssl_private_key_method_st operate on different private keys. I was trying to have another struct inherit from ssl_private_key_method_st and have the sign/decrypt/complete methods operate on instance variables of the inherited struct.

I am aware of using SSL_[sg]et_ex_data to pass data to these functions indirectly, but I was looking for a more simpler / direct way of passing instance data to these functions if possible.

1
  • Which event are you trying to subscribe? The api provided the SSL_CTX structure to store the context. Commented May 21, 2019 at 5:52

4 Answers 4

2

You are running into undefined behavior.

TypeFoo and bar are different types of function pointers (int (*)(int) and int (NB::B::*)(int) respectively). While it is possible to cast one to the other, using the result to call the function will result in undefined behavior.

8.2.10 Reinterpret cast [expr.reinterpret.cast]
...
6. A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type (11.3.5) that is not the same as the type used in the definition of the function is undefined. —end note ] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: See also 7.11 for more details of pointer conversions. —end note ]

Sign up to request clarification or add additional context in comments.

Comments

2

Short answer: you don't.

Non-static member function pointers are weird. Calling one involves a secret this parameter, and they may or may not be virtual. This makes them impossible to mix with ordinary function pointers.

You should consider using std::function<int(int)> instead of int (*)(int). This would allow you to store something like the following lambda:

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

This lambda captures the current object by reference, and this reference is stored inside the std::function object itself. But you can just as well assign any other function to a std::function, directly or through a lambda or bind expression.

On the other hand, if your bar method doesn't really doesn't depend on an instance, just make it static. This will allow it to mix with regular function pointers, since it no longer needs a secret this and cannot be virtual.

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

Written like this, &B::bar can be assigned to a regular int (*)(int) function pointer.

5 Comments

The base class is from a 3rd party standard library, so I cannot change the signature of member function foo.
Sadly, I need bar to be a non-static member.
@vrtx54234 I'm afraid you are hooped.
@vrtx54234: Try to explain your task. I believe that the 3rd party had a valid use case in their mind. What's the difference between what they have designed and what you are trying to achieve?
@DmitryKuzminov updated the question with the specific use-case I am trying to address.
1

Your TypeFoo defines a pointer to a regular function while bar is a method. Each non-static method has an implicit first parameter this.

So you should decide what do you need: a regular function (in this case make the bar static) or a method, in this case you should typedef like that:

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

The reinterpret_cast is an error prone practice. If you cannot cast without it - there is high probability that your code is not correct.

Comments

0

Invoking a member function pointer is a real pain. I suggest you go about this the following way, simplifying much of the context handling:

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

3 Comments

My bad, I should have mentioned this in my original posting clearly. I want the main to be this way: NA::A *a = new NB::B(); std::cout << a->foo(2) << std::endl; Looking at all the responses, it looks like this problem cannot be solved.
Well, if it's of any help, I've updated my answer for the change in main() of your question. It works but can't say if it'd server your purpose without further details. Please see for yourself.
Unfortunately, I will only be register object B with another library which will be invoking ((A)B).foo(), so I do not have control over how foo is called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.