3

I have a weird issue using polymorphism. I have a base class that implements a static method. This method must be static for various reasons. The base class also has a pure virtual method run() that gets implemented by all the extended classes. I need to be able to call run() from the static class.

The problem, of course, is that the static class doesn't have a this pointer. This method can be passed in a void * parameter. I have been trying to come up with a clever way to pass the run method into it, but nothing has worked so far. have also tried passing this into it. The problem with this is that I would then have to instantiate it, which requires knowledge of the extended class. This defeats the whole purpose of the polymorphism.

Any ideas on how to go about this?

unwind
  • 391,730
  • 64
  • 469
  • 606
Ori
  • 4,961
  • 10
  • 40
  • 39
  • 3
    I think you mean "static method" last in the first paragraph? – unwind Oct 09 '09 at 14:44
  • 1
    Ori, you object to passing `this` to the static method because "I would then have to instantiate it," but you want to call the virtual `run` method. You can't call a virtual method without an instance, so you would have to instantiate the class anyway. The static method doesn't need to know *which* class was instantiated; it's just receiving a base-class pointer, as Chris's answer demonstrates. – Rob Kennedy Oct 09 '09 at 15:13

4 Answers4

10

Don't pass it as a void* pointer, pass it as a pointer (or reference) to the base class:

class BaseClass
{
public:
  static void something(BaseClass* self) { self->foo(); }
  virtual void foo() = 0;  
};
ChrisW
  • 54,973
  • 13
  • 116
  • 224
5

This usually happens when you have to squirrel your C++ objects through a C API. A classic example is a thread class.

Here's the standard idiom for doing this:

/** calls thread_func in a new thread passing it user_data as argument */
thrd_hdl_t c_api_thread_start(int (*thread_func)(void*), void* user_data);

/** abstract thread base class
* override my_thread::run to do work in another thread
*/
class my_thread {
  public:
    my_thread() hdl_(c_api_thread_start(my_thread::thread_runner,this)) {}
    // ...

  private:
    virtual int run() = 0; // we don't want this to be called from others

    thrd_hdl_t hdl_; // whatever the C threading API uses as a thread handle

    static int thread_runner(void* user_data)
    {
      my_thread* that = static_cast<my_thread*>(user_data);
      try {
        return that->run();
      } catch(...) {
        return oh_my_an_unknown_error;
      }
    }
};

Would that help?

sbi
  • 219,715
  • 46
  • 258
  • 445
  • nice snippet, but isn't it better to use `static_cast` to cast from `void*` to another pointer? – Eli Bendersky Mar 29 '11 at 07:09
  • @Eli: Oops. Can you do that? I didn't know. If you're sure, I'll certainly change it. (Feel free make the change yourself.) – sbi Mar 29 '11 at 09:25
  • you certainly *can* do that (since `void*` is statically cast-able to any pointer). But whether you want to is really a matter of good practice. See http://stackoverflow.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-whatever Since it's your answer I'll let you decide :) – Eli Bendersky Mar 29 '11 at 13:42
  • @Eli: Thanks, that's an interesting discussion. FWIW, I changed my answer. Thank you for pointing out this issue! – sbi Mar 29 '11 at 15:17
3

Why not pass a reference to the object in rather than the method e.g.

static void func( BaseObject& o)
{
     o.run();
}
mmmmmm
  • 32,227
  • 27
  • 88
  • 117
1

IMO, your best bet is to get rid of the static method. Find a way around that and you're golden.

Randolpho
  • 55,384
  • 17
  • 145
  • 179