Pointers to vitrtual and non-virtual member functions.

Started by
10 comments, last by Dmytry 19 years, 8 months ago
I have a question: I've used pointers to class member functions in Object Pascal, and now i'm developing in C++ , what differences both does have? Additional information: currently i'm writing some kind of event/message system for some project that might be game-related a bit. I want to write "event source" class that will have a list of event receiving functions (edit, clarification : i meant,list of event listeners. That listeners will be members of classes. One class may need to have more than one listener, so i can't just inherit listeners from some parent class.). and will call everyone in the list with some parameter (pointer to event structure) when some event is sent to it. Then i'll create different event sources for input , and for internal events/messages such as "startup","shutdown","Video_before_reinit", "Video_after_reinit" (have to reinitialize some opengl thingies when window is resized or something), separate event sources for system-dependent messages and system-independent ones, and so-on, for user-input logic as well. ( so question 2, is it a good idea? ) I also want to do it like i did similar things before, it will be faster to develop. additional information about ObjectPascal: I myself see some principial differences between Object Pascal's pointers to class member functions (called variables of procedural types or something like that) and C++'s ones. In Object Pascal, i can do type ProcType=procedure(a:real) of object; var proc:ProcType; then if i have instance of object "MyObjectInstance" with a member function1 "MyObjectMethod" that takes real as parameter,and have same calling convention, i can do proc:=MyObjectInstance.MyObjectMethod; ... proc(1.0); and it will call to MyObjectInstance.MyObjectMethod(1.0) . How it works in Object Pascal: that procedural variable hold pointer to instance and pointer DIRECTLY to method (it finds method to call to when value is assigned,i.e. when operator ":=" is executed) . When i'm calling using that variable, it pushes (or places into register) pointer to instance and then calls that method, at this time it doesn't use VirtualMethodTable,and it's just plain call-by-reference. In C++ different things happens... I wrote testcode (not exactly that names, but kinda similar):

// i have MyClass with virtual member Member() and MyClassChild that inherits from MyClass and Member()

typedef void (MyClass::*PointerToMember)(); // c++ have _inconsistant_ sintax for type definition....
...
...
MyClass myClassInstance;
MyClassChild myClassChildInstance;
PointerToMember pointerToMember=(&MyClass::Member);
// this gives compiler error:
// PointerToMember pointerToChildMember= &ChildClass::Member);
// and it works:
PointerToMember pointerToChildMember=static_cast<PointerToMember>(&ChildClass::Member);
...
...
(myClassInstance.*pointerToMember)();

(myClassChildInstance.*pointerToMember)(); 



Last statement works and what's surprising and strange, calls child's Member() ,not parent's , but i worry that somewhere it will not work. Will it work anywhere? differencies i found:: First, it looks like my PointerToMember should surely works only with MyClass. Or not. Need to know. Second, i have to specify instance myself. Ok,no problem with this one, i'll make struct that holds instance pointer and pointer to method. Third, as it calls child's Member() , what may be a good surprise for me, but it looks rather inefficient- instead of one assembler instruction, call-by-reference, it looks like that pointer to virtual class member holds in fact not a pointer but index in VMT and when calling it work as read pointer to VMT from instance add index to that pointer read pointer where to call to call I don't know if it's implementation-specific or not. I've readed about so-called "functors"2, and have humple opinion about 'em: I3 will feel myself rather stupid if this will do virtual member call to functor read pointer to VMT from instance add index to that pointer read pointer where to call to call (and not to mention one unnecessary return and one unnecessary stack frame) to simulate what should be done by _single_ call by reference. Is there any other way? I know that i can swich to java-style ...perversionism... and write something like "EventListener" class with overloadable method "ProcessEvent",and make everything derive from it . But i can't use this "solution" for some other reasons. footnotes: 1: it's named "Method" in Object Pascal 2: ritorical question:what it does have with functors? probably same what "classes" have with classes... 3: there, ego said: "..I,real programmer that invented xoraddjumping OISCVM,will have to do such thing?..." ;) [Edited by - Dmytry on September 4, 2004 1:44:36 PM]
Advertisement
Damn, pass your text thru a spell checker, but anyway. Pointers to members in C++ are braindead and limited and they weren't designed with what you have in mind. You can't assign methods of a child class to a pointer to member of an ancestor class without a reinterpret_cast (all other casts are illegal) and once you cast, you can't do anything without it besides casting it back, thus making the whole thing pointless.
Trust me, you don't want to mess around with this. boost::function is what you're looking for.
Quote:Original post by fallenang3l
You can't assign methods of a child class to a pointer to member of an ancestor class without a reinterpret_cast (all other casts are illegal) and once you cast, you can't do anything without it besides casting it back, thus making the whole thing pointless.
Trust me, you don't want to mess around with this.


that is true but you can get in-direct polymophic behaviour through pointers to member functions, the way you do it its just not what people would expect, i think this example will clarify everything to Dmytry

it demonstrates:

direct & in-direct non-polymorphic calls and
direct & in-direct polymorphic calls

#include <iostream>struct base {   virtual void do_it() const {      std::cout << "HI I'M BASE\n";   }   virtual ~base() {}};struct derived : base {   void do_it() const {      std::cout << "HI I'M DERIVED\n";   }};int main() {   typedef void (base::*base_mem_ptr)() const;   typedef void (derived::*derived_mem_ptr)() const;   base b1;   derived d;   const base* b2 = &d;   base_mem_ptr m = &base::do_it;   derived_mem_ptr m2 = &derived::do_it;   std::cout << "all forms of non polymorphic calls:\n";   //direct non-polymorphic call   b1.do_it();   //direct non-polymorphic call   d.do_it();   //in-direct non-polymorphic call   (b1.*m)();   //in-direct non-polymorphic call   (d.*m2)();   //in-direct non-polymorphic call through derived type using base pointer to member functions   (d.*m)();//////////////////////////////////////////////////////   std::cout << "\nall forms of polymorphic calls:\n";   //direct polymorphic call   b2->do_it();   //in-direct polymorphic call through base pointer type   (b2->*m)();   return 0;}
Quote:Original post by fallenang3l
Damn, pass your text thru a spell checker, but anyway. Pointers to members in C++ are braindead and limited and they weren't designed with what you have in mind. You can't assign methods of a child class to a pointer to member of an ancestor class without a reinterpret_cast (all other casts are illegal) and once you cast, you can't do anything without it besides casting it back, thus making the whole thing pointless.
Trust me, you don't want to mess around with this. boost::function is what you're looking for.

Passing your text through a spell checker would reveal several grammatical and spelling errors of your own. If you really care that much about it, perhaps you should look into improving?
Here is a class that I've written that does what you're looking for. It uses the boost::function library to turn class functions into function objects and uses templates to make it completely generic. It could definitely be extended as right now it is hard-coded to only accept functions with one argument, but you could do that with partial template specialization and have as many arguments are you wanted.

The boost library also has something for this type of problem they've done, too, in boost::signal. I've never used it, but it might be worth checking out.
Quote:Original post by Tim Cowley
Passing your text through a spell checker would reveal several grammatical and spelling errors of your own. If you really care that much about it, perhaps you should look into improving?


You crack me up son.
Thanks everyone :)

but,hmm,is there any way to just only get adress of function to be called?
I mean, get adress of b() to be called in expression
A* a;
.....
a->b()
,get that adress from a->'s vmt.

I'm sure i can do it with assembly and only need to look at code compiler generates. I probably will do exactly that, with a way to use other <s>hacks</s> solutions such as boost::function ... i looked at boost::function, their code also contains various workarounds for every compiler, so i think asm is perfectly OK).

It's strange that in language that is supposed to be most powerful, you have to use wrappers-inside-wrappers and tonns of templates, to inefficiently simulate what must be done by single call-by-reference. and is done by single call by reference in other not-so-powerful OO language. Kinda like using cooladd.

I probably will also look at Borland C++ 's VCL , it's literally the same as Borland Delphi's VCL(uses what i want), interesting what workaround do they use.


. C++ gives you power to shoot _the_compiler_. And reuse the bullet .
Quote:Original post by fallenang3l
Quote:Original post by Tim Cowley
Passing your text through a spell checker would reveal several grammatical and spelling errors of your own. If you really care that much about it, perhaps you should look into improving?


You crack me up son.

I wish I could reciprocate, but you just bore me.
Quote:Original post by Tim Cowley
Quote:Original post by fallenang3l
Quote:Original post by Tim Cowley
Passing your text through a spell checker would reveal several grammatical and spelling errors of your own. If you really care that much about it, perhaps you should look into improving?


You crack me up son.

I wish I could reciprocate, but you just bore me.


Since you're so bored, maybe you should wake up because I'm not laughing with you.
Quote:Original post by Dmytry
Thanks everyone :)

but,hmm,is there any way to just only get adress of function to be called?


Mmmm. Difficult and non standard at all. And, given that, the incredibly shameless plug : have a look here :)

I didn't manage to get the virtual functions now (harder... I have to parse the assembly in order to get the vtl offset, then I must find the vtl itself, and hopefully I'll be able to get the adress of the virtual function). Not as easy it it should be...

And passing my text thru a spell or grammar checker would generate a lot of problems too, but since you can easily understand (I hope) what I say, then where is the exact problem ? English is not my mother tongue, and I suspect that if you are not french, then I'll be better at french than you. Dmytry's question IS understandable too, as well as fallenang3l and Tim's statements, so what is the real problem ? (oh guys, do not answer that stupid question, and stop fighting, because this is ignating and I do not want it to ignate).

Regards,

This topic is closed to new replies.

Advertisement