How can I get the address of a virtual member function?

R

Roy Yao

Hello,

I need to pass a pointer to a
callback function to the lower
level modules. But the function
is thought to be a virtual member one.

How can I get the real address of
the virtual member function?

Best regards,
Roy
 
V

Victor Bazarov

Roy Yao said:
I need to pass a pointer to a
callback function to the lower
level modules. But the function
is thought to be a virtual member one.

How can I get the real address of
the virtual member function?

There is no difference of getting the address
of a member function based on its virtuality.
The way the address is used will determine
which function is actually called. The syntax
for getting the address of a member is

& <class-name> :: <member-name>

for example:

struct A {
virtual int foo() { return 42; }
};

struct B : A {
int foo() { return 73; }
};

int main() {
B b;
A& a = b;
int (A::*amem)() = &A::foo; // take address
return (a.*amem)(); // use the address
}

(the program above should return 73 to the hosting
environment)

BTW, what problem are you encountering?

Victor
 
R

Roy Yao

Hello, Victor,

Thanks at first.

The problem troubling me is that I must convert a virtual member function
pointer to a non-member function pointer in order that other modules can
call the virtual member function without an object( that is the "this"
pointer is not needed in my virtual member function).

Can you catch my idea?

Roy
 
S

Shane Beasley

Roy Yao said:
The problem troubling me is that I must convert a virtual member function
pointer to a non-member function pointer

You cannot do this in C++.
in order that other modules can
call the virtual member function without an object( that is the "this"
pointer is not needed in my virtual member function).

First, a member function which does not use the "this" pointer should
not be a member function (or, at least, it should be a static member
function). Second, all virtual function calls use the "this" pointer
to determine which implementation to call.

As such, you can do what you want by breaking up the virtual function
into a static member function and a virtual function which calls it:

class Base {
public:
virtual void f () = 0;
virtual ~Base ();
};

class Derived : public Base {
public:
static void do_f ();
void f () { do_f(); }
};

Then pass &Derived::do_f instead.

However, that's not how you'd normally deal with a properly-written
C-style callback API. Such an API would take a pointer to a function
and a pointer to data to be passed to that function:

typedef void *cb_data_t;
typedef void (*cb_func_t) (cb_data_t);
void do_callback (cb_func_t f, cb_data_t x); /* calls f(x) */

To this API, pass a pointer to an object and a pointer to either a
static member or a non-member function which calls the desired member
function on the object:

class MyClass {
public:
void f ();
};

void call_f (cb_data_t p) { static_cast<MyClass *>(p)->f(); }

int main () {
MyClass obj;
do_callback(call_f, &obj);
return 0;
}

Note that you have to be really careful when you do this with
inheritance:

class Base {
public:
virtual void f () = 0;
virtual ~Base ();
};

void call_f (cb_data_t p) { static_cast<Base *>(p)->f(); }

class Derived : public Base {
public:
virtual void f ();
};

int main () {
Derived obj;

// WRONG: call_f expects Base *; we're passing Derived *
do_callback(call_f, &obj);

// RIGHT: pass Base * as expected
do_callback(call_f, static_cast<Base *>(&obj));
return 0;
}

In theory, conversion of Derived * to void * to Base * is undefined.
In practice, it probably will work unless multiple or virtual
inheritance is used. In any case, I suggest that you not take any
chances -- convert to Base * before passing. If you don't like casts
(who does?), you can write a wrapper like this instead:

// guarantees that x is a Base *
void do_base_callback (cb_func_t f, Base *x) { do_callback(f, x); }

int main () {
Derived obj;
do_base_callback(call_f, &obj);
return 0;
}

- Shane
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,143
Messages
2,570,822
Members
47,368
Latest member
michaelsmithh

Latest Threads

Top