Solved

Object's method as a callback method

Posted on 2000-05-07
14
313 Views
Last Modified: 2010-04-02
It there a way to use object's method as
a callback method if I don't know what type
of that object is? Is there any other way
than to use normal non class method,
i.e. normal function as a callback function.

e.g.
void foo(void *pObject)
{
  SomeClass object;

  object = (SomeClass *) pObject;
  object->method();
}

If I know pObject is type of SomeClass,
I can cast it with no problems. But what
if I don't know the type? Is there a way
to find out this type or pass it as a variable?

Why I'm asking this, is because I have
class library which uses this callback method.
So far I have defined that "User must give
pointer to object which implements
method called "foo()". I can't say that
"User must implement class which name
is X and implement a method foo there",
because most of the time users of the
class library would have to make this
class just for that one method.
0
Comment
Question by:tonitop
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
14 Comments
 
LVL 3

Expert Comment

by:mnewton022700
ID: 2787068
Would you be able to force user's to derive their own class from a class of yours?

You could make an abstract class with a pure virtual method that your users need to override.

That way you can easily call this method from your code with objects they pass to you.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 2787667
You could simply implement exactly what you have using a template method, like this:

template <typename T>
void f(T* object)
{
    object->foo();
}

users will just be able to call this method using whatever class they like (as long as it implements foo), like this:

SomeClass sc;
f(&sc);

0
 

Author Comment

by:tonitop
ID: 2787952
Hmm a question. What would happen if I try to call
object->foo() and such method does not exists?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Expert Comment

by:jasonclarke
ID: 2787957
>  What would happen if I try to call
object->foo() and
> such method does not exists?

The program would not compile.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 2787964
Here is an example, to try:


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

class B {
};

template <typename T>
void foo(T* object)
{
    object->foo();
}

void main()
{
   A a;
   B b;
   foo(&a);  // should compile OK
   foo(&b);  // will not compile
   int c;
   foo(&c);  // will not compile
}
0
 

Author Comment

by:tonitop
ID: 2788002
Somethign wrong here. I tested this in simple program by
writing

template <class T> void f(T *object);

..
..
..
int main()
{
..
..
..
}

void f(T *object)
{
   object->foo();
}

Now I get errors:
Error: T is not defined.
Error: object is not defined.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 2788008
The function must be defined with the template info, like this:

template <class T>
void f(T *object)
{
   object->foo();
}
0
 

Author Comment

by:tonitop
ID: 2788067
But I can't use this inside a class? I have method
Receive() in my class. In this method user must specify pointer to an object which implements method foo.

//A.hh
class A
{
    public:
      void Receive(T *object);
};

//A.cc
template <class T>
A::Receive(T *object);
{
   object->foo();
}

This gives me an error "T is not defiend" in A.hh.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 2788181
You can, you have what are then called member function templates.

However, compiler support for this is a bit limited.  With MSVC++ 6, it seems that you have to define the template method body inside the class, so your class would look like:

class A
{
    public:
      template <class T>
      void Receive(T *object)
      {
          obect->foo();
      }
};
0
 

Author Comment

by:tonitop
ID: 2789823
Ok. This seems to work. However when I try this, I get an error:

class A
{
  public:

    template <class T>
    void Receive(T *object)
    {
        obect->foo();
    }

   template <class T>
   void SetPointer(T *obj)
   {
       object = obj;  // Error here
   }

   template <class T>
   void ReceiveResponses()
    {
           object->foo();
    }

private:
    template <class T>
    T *object;
 
};

In main I have:

#include <iostream.h>

#include "A.hpp"
#include "B.hpp"

int main()
{
   A a;
   B b;
   a.SetPointer(&b);
   return 0;
}

Visual C gives me error:
error C2440: '=' : cannot convert from 'class B *' to 'template-parameter-1 *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

If I replace *object with object (and *obj with objc),
Visual C gives me error:
fatal error C1001: INTERNAL COMPILER ERROR

I need to pass this pointer before it is used, since it is used inside thread and there is no way to know when it will be used first time.
0
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2790098
Can you give a bit more?

I suppose you pass a function pointer to the library, which then calls (back) that function. Can you give the signature of the function, or its typedef?

When the library calls that function, it passes a void* which could in fact point to some object? I suppose you pass in that object somewhere.

As example, I'll use qsort from stdlib.h, which requires a funct of the type
int (*)(const void*, const void*)

A solution for this qsort function could be:

#include <stdlib.h>

typedef int (*PF)(const void*, const void*);
// declares PF to be a pointer (the *) to a function that
// returns an integer and take two const void*'s as arguments

template<typename T>
int compare(const void* p1, const void* p2)
{
     const T* t1 = reinterpret_cast<const T*>(p1);
     const T* t2 = reinterpret_cast<const T*>(p2);
    return t1->compare(*t2);
}

class A
{
    public:
       A(double d) : data(d) {}
       A() : data(0) {}
       int compare(const A& other) const;
   private:
      double data;
};

int A::compare(const A& other) const
{
   return int(data - other.data);
}

void f()
{
    A array[10];
    qsort(array, 10, sizeof(A), compare<A>);
}

//It is even possible to drop the constraint on the name
// of the member function by giving it as a non-type argument to the
// template. The syntax is ugly and, though g++ compiles it,
// I am not sure it is legal to use the T parameter in
// other parameters. Any input here jason, nietod?
// int (T::*PMF)(const T&) const
// returns int, takes const T&
// T::*PMF means PMF is a pointer to a member of T
// the closing const declares it as a const member func

template<typename T, int (T::*PMF)(const T&)const>
int compare(const void* p1, const void* p2)
{
     const T* t1 = reinterpret_cast<const T*>(p1);
     const T* t2 = reinterpret_cast<const T*>(p2);
     return (t1->*PMF)(*t2);
}

// luckily it is easier to use the template

void g()
{
    A array[10];
    qsort(array, 10, sizeof(A), compare<A, &A::compare>);

}

If this is close to your problem, let me know and do give the details on the call back function signature and use by the library.
0
 

Author Comment

by:tonitop
ID: 2791051
I'll pass a pointer to object which implements method foo().
Class B is just:

#include <iostream.h>

class B
{
public:
    void foo() { cout << "foo" << endl; }
};

So I use A's method SetPointer to pass that pointer and
when I wan to use it, I'll call A.Receive().

It seems that CC (that's the compiler I'm using on solaris) is
picky about templates.

"A.hh", line 5: Error: Templates can only be declared at the global level.

Same error comes on every line in A.hh where I have
template <class T>

0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 2791673
You seem to have a straight template class now, try:

template <class T>
class A
{
  public:
    void Receive(T *object)
    {
        obect->foo();
    }

   void SetPointer(T *obj)
   {
       object = obj;  // Error here
   }

   void ReceiveResponses()
    {
           object->foo();
    }

private:
    T *object;
};

#include <iostream.h>

#include "A.hpp"
#include "B.hpp"

int main()
{
   A<B> a;
   B b;
   a.SetPointer(&b);
   return 0;
}

but this instance of A can obviously only handle Bs then.
0
 
LVL 9

Accepted Solution

by:
jasonclarke earned 100 total points
ID: 2791722
You are correct about the member function signature KangaRoo.  The method I have used to encapsulate this sort of callback is this:

class Client {
public:
    void foo() {};
    void bar() {};
};

class AbstractCallback {
public:
   virtual void operator()() = 0;
};

template <class T>
class Callback  : public AbstractCallback
{
public:
    typedef void (T::*callback)();
    Callback(T* object, callback cb)
       : mObject(object), mCB(cb) {}
    virtual void operator()()
    { (mObject->*mCB)(); }
private:
    T*  mObject;
    callback mCB;
};

class A
{
  public:
    A(AbstractCallback* cb)
        : mCB(cb) {}

    void Receive(AbstractCallback* cb)
    {
        (*cb)();
    }

    void ReceiveResponses()
    {
        (*mCB)();
    }
private:
    AbstractCallback* mCB;  
};


void main()
{
    Client c;

    Callback<Client> cb1(&c, Client::foo);

    A a(&cb1);  // will call foo

    a.ReceiveResponses();

    Callback<Client> cb2(&c, Client::bar);

    a.Receive(&cb2); // will call bar
}

This has the advantage (or maybe disadvantage depending on the circumstances) that the method to be called is up to the client.

Have a look at this example and if you think it might be what you want, let me know and I will supply more help if you need it.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question