Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to replace a method at runtime?

I want to make a plugin system with the capability to override a method at runtime.

Some answers say function pointers, but how about a defined function or class?

Like this:

class foo
{
  public:
    bar(int foobar);
}

Is there a way to get function pointer for that, or replace it?

BTW, hooking is not considered an answer because it's very platform specific and dangerous.

like image 280
Tatsuyuki Ishi Avatar asked Apr 15 '15 08:04

Tatsuyuki Ishi


3 Answers

To make a plugin system you don't need to replace a method of a class at runtime.

You can replace what the method does by using polymorphism or any other way to configure an object.

Check out the answers to the following question: What's safe for a C++ plug-in system?

like image 181
Dmitry Ledentsov Avatar answered Sep 21 '22 13:09

Dmitry Ledentsov


Runtime function "replacement" can be achieved with one of several techniques:

  1. Polymorphism
  2. Standard library facilities such as std::function
  3. Third party libraries or platform specific techniques to translate or dispatch function calls.

On which option is better is highly dependent on the intended use and target environments. For example; plugin systems could well make use of polymorphism (with the appropriate factories and possibly even combined with the template method pattern) whilst internal function routing could use std::function.

These techniques wouldn't really "replace" any of the functions, but rather can be set up at runtime to route the function call as required.

Note I've focused on the C++ aspects of the question (it was tagged C and C++ but the sample code is C++).

like image 22
Niall Avatar answered Sep 18 '22 13:09

Niall


While you can't directly replace a method, this can be solved with another layer of indirection.

#include <iostream>
#include <functional>

class Foo
{
private:
    void default_bar(int value)
    {
        std::cout << "The default function called\n";
    }
    std::function<void(Foo*, int)> the_function = &Foo::default_bar;
public:
    void replace_bar(std::function<void(Foo*, int)> new_func)
    {
        the_function = new_func;
    }
    void bar(int value)
    {
        the_function(this, value);
    }
    void baz(int value)
    {
        std::cout << "baz called\n";
    }
};

void non_member(Foo* self, int value)
{
    std::cout << "non-member called\n";
}

int main()
{
    Foo f;
    f.bar(2);
    f.replace_bar(&Foo::baz);
    f.bar(2);
    f.replace_bar(non_member);
    f.bar(2);
    f.replace_bar([](Foo* self, int value){ std::cout << "Lambda called\n"; });
    f.bar(2);
}

Currently this replaces the method of the instance. If you want to replace the method of a class, make the_function static (even better, make it a static method returning a static variable to avoid static initialization order fiasco)

like image 34
milleniumbug Avatar answered Sep 19 '22 13:09

milleniumbug