Sign in to follow this  
yacwroy

pointer to virtual function of a instantiated object

Recommended Posts

Hi. I have a instance "c" of a class "C" derived from a known class "A". This known class has a virtual function "foo". I want to get a function pointer to the derivation of "foo" for "c"s class, except I don't have access to "C" since it is externally defined. ie: fp = &(c->foo); "fp" now equals "&(C::foo);"
class A {
  public:
    virtual void foo() {}
};

class B : public A {
  public:
    void foo() {}
};

class C : public A {
  public:
    void foo() {}
};

bool test() {
    A* b = new B();
    A* c = new C();

    if(&(b->foo) == &(B::foo)) ::std::cout << "b is a B"; // ### Fails to compile.
    if(&(c->foo) == &(B::foo)) ::std::cout << "c is a B"; // ### Fails to compile.
    if(&(c->foo) == &(C::foo)) ::std::cout << "c is a C"; // ### Fails to compile.
};

Unfortunately, I get this error when compiling the above ### lines. "ISO C++ forbids taking the address of a bound member function to form a pointer to member function." It's in the "&(b->foo)" bit - I split it into two lines to check. (PS: why don't compilers ever give column number?) Is the above error avoidable? Physically there shouldn't be an issue, it's simply a vtable lookup, right? I would prefer not having to define an extra virtual function that simply returns the function pointer or some other type-identifying value. NOTE: This is an attempt to avoid using RTTI compiler flags. The code deals with incoming serialized data for externally-defined types. Thanks for your help.

Share this post


Link to post
Share on other sites
I'm no expert, but &(B::foo) does not make sense to me if foo is not a static method. Where do you think this would be in memory? It has no reference to any instance so why would it equal &(b->foo)? For that matter, wouldn't &(b->foo) == &(B::foo) and &(c->foo) == &(B::foo) seem a little... disastrous?

Share this post


Link to post
Share on other sites
#include <iostream>

struct Base {
virtual ~Base() { }
virtual void foo() { std::cout << "Base\n"; }
};

struct Derived : Base {
virtual void foo() { std::cout << "Derived\n"; }
};

int main() {
Base* b = new Base;
Base* d = new Derived;

void (Base::*pointer)() = &Base::foo;

(b->*pointer)();
(d->*pointer)();

delete d;
delete b;
}

This outputs
Base
Derived

Share this post


Link to post
Share on other sites
Quote:
Original post by yacwroy
NOTE: This is an attempt to avoid using RTTI compiler flags. The code deals with incoming serialized data for externally-defined types.
Explain exactly what problem you are trying to solve. There's probably a better way to do it. There's no way to implement your proposed solution in standard C++. You can approximate it by taking advantage of platform specific features, but then you're really locking in to a small set of compiler implementations.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
NOTE: This is an attempt to avoid using RTTI compiler flags. The code deals with incoming serialized data for externally-defined types.

How come you don't want to use the built in RTTI? Are you stuck with a crappy compiler or something?

Using the standard RTTI would be a lot easier ;)
if(dyanmic_cast<B*>(&b)) ::std::cout << "b is a B";

Most custrom RTTI implementations that I've seen add a public member or a virtual function to each class that points to a node in a static type-info object tree. Usually macros are used to construct the static tree...

Share this post


Link to post
Share on other sites
Thanks for the replies.

Looks like it mightn't be do-able and I might switch to RTTI.




jjd:
&(B::foo) should be a pointer to the function for the code that you write when you write void B::foo() { "blah" }; Is that right? If foo is virtual?

So if d was a B and d->foo() was going to call the above "blah", then to me it seems that &(d->foo) should point to the same place as &(B::foo), cos they both point to the same function, and thus &(d->foo) == &(B::foo). However, typecasting might screw things up.

BTW: B::foo == &(B::foo) for some wierd reason, it's just alternative syntax - if I understood
"http://www.oopweb.com/CPP/Documents/FunctionPointers/Volume/CCPP/FPT/em_fpt.html correctly.



oxyd:
I'm after a pointer to the concrete post-vtable function. I want only d's version. I'd want the output there to look like: Derived, Derived. Except I don't have access to the class Derived at compile time (It might be from a runtime-loaded module).

Basically, it's like asking: Please tell me what function will be called if I call d->foo().



hodgman:
Is it ok to mix RTTI and non-RTTI code, or RTTI code from different compilers, or will I lose any platform-independance by enabling RTTI?
Typically I would just prefer to not load in extra compiler options, libraries etc if it is possible to do without and suffer no loss, but perhaps I'm being too hasty.
The alternative here is to just have the class return a unique identifier from some virtual function, but that's less tidy and less efficient.
I'm still thinking on RTTI tho.
About custom RTTI trees: Yes, this is effectively custom RTTI but it would be a very tidy one with zero additional requirements for add-in module coders.



enigma:
Every descendant of a class with virtual functions has effectively already got an (albeit hidden) RTTI value - the vtable pointer.
However it's difficult and ugly to extract the vtable pointer of an object instance.
So I went for the next best thing - a member of the vtable of the object instance. However, the members of the vtable are all function pointers (#1).
This would uniquely identify the class if it's derived directly from the base class, as my foo() is abstract (=0). (Perhaps it wouldn't uniquely identify grandchildren but that is ok here).
I wasn't actually sure if I just had the syntax b0rked. I think you should be able to do this but it's not a major issue to me if it's not implemented. However, it's definately (and easily) implementable.

PURPOSE:
The purpose is to simply test whether "A* a" is really a "B" so that I can safely typecast.

It's actually not quite serialization but it's similar. The serial data is already parsed into a data tree of mixed types. This tree is then available for browsing (like a parsed JSON data-tree if you know what JSON is - or like XML except the leaves can be specific types like integer or text, which become different classes).

When the client browses the tree it asks for a member of type X named "name", eg:
::std::string name = branch.getText("name");
int age = branch.getInteger("age");
If the "age" member exists it might not be an integer, so casting to an integer to access the "int m_value" member would be wrong. So I need to check that "age" is an nm::AInteger (nm::AInteger is derived from nm::AElement);



(#1) Aside:
I just wish there were virtual static variables. Would make life soo much easier, and they kinda feel like they should be there. I mean, virtual functions are effectively like virtual static function pointers.

Share this post


Link to post
Share on other sites
Quote:
Original post by yacwroy
PURPOSE:
The purpose is to simply test whether "A* a" is really a "B" so that I can safely typecast.

Like this?:
void foo(A * a)
{
B * b = dynamic_cast<B *>(a);
if (b)
{
std::cout << "a is a B" << std::endl;
}
else
{
std::cout << "a is not a B" << std::endl;
}
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this