Method pointers and inheritance

Started by
6 comments, last by mputters 20 years, 7 months ago
Hi, say I have this :

struct Base
{
  typedef void (Base::* TEST)( void );
};
struct Derived : public Base
{
  void hello( void );
};
int main()
{
  Base::TEST p = &Derived::Hello;
};
I get an error that the conversion can't be done (Visual C++ 7.1) : "Cast from base to derived requires dynamic_cast or static_cast" Of course, with a static_cast it works, but I'd like to know why that cast and where I'm casting from base to derived (if there was a cast, it'd be from derived to base, I guess), and why I would use a dynamic_cast on a method pointer... Edit: forgot the inheritance [edited by - mputters on September 21, 2003 3:24:06 PM]
Advertisement
Because it doesn''t make sense to convert from a child''s member function pointer type to a base''s member function pointer type. If you were able to do that, then you would be able to call a child''s member function when using a base object, which would be very very bad and doesn''t make any logical sense (not to mention that the function would often times try to manipulate datamembers of the child which don''t even exist in the parent).

The VALID conversion is from a base member function pointer to a child member function pointer.

Basically I just wanted to use them as callbacks that would be called from the base...
It works with a static_cast, but it looks ugly..
quote:Original post by mputters
Basically I just wanted to use them as callbacks that would be called from the base...
It works with a static_cast, but it looks ugly..


I plead with you, do not do this. While a static_cast will get rid of any compile time errors, you can''t be sure of what will happen at runtime because the child''s member function can manipulate non-base datamembers and do other functions that may not mesh well with the implementation of the base. Post a more descriptive version of the problem. A better solution is more likely using static member functions which take pointers to the base as their parameter for your callbacks.
Well, that''s what I''d like to avoid. Basically just add a AddCallback( Base *, TEST ) method to Base, and I''d like to do somebase.AddCallback( somederived, &Derived::hello );..
quote:Original post by mputters
Well, that's what I'd like to avoid. Basically just add a AddCallback( Base *, TEST ) method to Base, and I'd like to do somebase.AddCallback( somederived, &Derived::hello );..


Just change your test typedef to

typedef void (*TEST)( Base* );

and have your callback functions be funstions or static member functions which take a parameter pointer to base.

and then you can have a member function
AddCallback( Base *, TEST )

and would be able to do:
somebase.AddCallback( somederived, &Derived::Hello );

just like you said.

This way you get the exact functionality you want and it logically makes sense.

EDIT: Example

struct Base{  typedef void (*TEST)( Base* );  void AddCallback( Base *, TEST );};struct Derived  : public Base{  static void Hello( Base* );  };int main(){  Base Example;  Derived SomeDerived;  Example.AddCallback( &SomeDerived, &Derived::Hello );}


[edited by - Polymorphic OOP on September 21, 2003 4:12:57 PM]
I was bored, so here's an example that will work if you want to be able to set up an object and a corresponding member function of that level or lower in the type hierarchy (not always limitted to base). This may be what you want, but again, without more information I can't really tell. I wrote it out as if there could be only one callback to simplify the example, but you could always make an array or linked list, etc. of CallerBase's to store multiple callbacks. Your situation is awkward and requiring that the person to pass both a pointer to a type as well as a function makes it really pointless to force the person to derive from base (otherwise the child would have to contain the callback information as well, which it probably wouldn't be using). I commented out the relationships between the types and the base, but you can put them back in if you'd like, but I question why you'd want to.

#include <iostream>struct Base{public:  Base();  ~Base();  template< typename Derived >    void SetCallback( Derived& Object,                      void (Derived::*Function)() );  void Call();private:  class CallerBase;  template< typename Type >    class Caller;private:  CallerBase* Callback_m;};class Base::CallerBase{public:  virtual ~CallerBase() = 0;  virtual void Call() const = 0;};Base::CallerBase::~CallerBase(){}template< typename Type >  class Base::Caller    : public Base::CallerBase{public:  Caller( Type* Object_Init,          void (Type::*Function_Init)() );  void Call() const;private:  Type* Object_m;  void (Type::*Function_m)();};Base::Base()  : Callback_m( 0 ){}Base::~Base(){  delete Callback_m;}template< typename Derived >  void Base::SetCallback( Derived& Object, void (Derived::*Function)() ){  /*Base* Test;    Test = Object; */ // Compiler error if the Object isn't derived from base which you say you want, but shouldnt be necissary  delete Callback_m;  Callback_m = new Caller< Derived >( &Object,                                      Function );}void Base::Call(){  Callback_m->Call();}template< typename Type >  Base::Caller< Type >::Caller( Type* Object_Init,                                void (Type::*Function_Init)() )    : Object_m( Object_Init ),      Function_m( Function_Init ){}template< typename Type >  void Base::Caller< Type >::Call() const{  (Object_m->*Function_m)();}struct SomeDerived//  : Base{  void Hello()  {    std::cout << "Hello" << std::endl;  }};int main(){  Base Example;  SomeDerived Wee;  Example.SetCallback( Wee, SomeDerived::Hello );  Example.Call();};


Edit: If you want the types of callback to be related by inheritance then i suggest making "Base" templated and adding a virtual memberfunction to CallerBase for "GetObject" which returns a pointer to the object being operated on. Then in the Caller type define the function to return Object_m. This way, any objects/functions you use must be derived from the template parameter (not of Base). If that was confusing, tell me, and I'll post an example of that.

[edited by - Polymorphic OOP on September 21, 2003 5:26:58 PM]
I knew those ways already... but thanks anyway.

This topic is closed to new replies.

Advertisement