Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to detect if a function is overridden?

Suppose we have an abstract Base class that is inherited:

class Base
{
    protected:
        Base() {}
        virtual ~Base() {}
        virtual void on_event_foo(int) {}
        virtual void on_event_bar(int) {}
};

struct Concrete : public Base
{
        virtual void on_event_foo(int value) {/*do some stuff with @value*/}
};

Is it a way to know (at compile time would be the best) the virtual functions from Base that was overridden (with some code in constructor, or with a special pattern)?

My purpose is to implement a wrapper for a library that use some callbacks ; and if I can do check the overriden functions, I will create only the callbacks the user wants.

I want the user can choose the function he wants to override. Then in my code, I will create callbacks only for the overridden functions. The pure virtual functions are not a solution, because they cannot permit to create a concrete class without overriding all of them.

In the constructor of Base, for now, I connect a lot of static callback functions of Base within a C API. In those functions, I call the corresponding member function. For example, the callback function is static Base::EventFoo(/* ... */) that calls inside object->on_event_foo(/* .. */). This is because I cannot give a member function as a callback to a C library. But creating too much callbacks make my wrapper slower. So, I want to connect only the callback that the user wants, ie knowing the functions there are overriden by him.

like image 461
Boiethios Avatar asked Jun 02 '16 09:06

Boiethios


People also ask

How do you check if a method is overridden?

getMethod("myMethod"). getDeclaringClass(); If the class that's returned is your own, then it's not overridden; if it's something else, that subclass has overridden it.

What if function is overriding?

When the base class and derived class have member functions with exactly the same name, same return-type, and same arguments list, then it is said to be function overriding.

How can you prevent a function from being overridden?

In C++, there's no way to forbid it, it's just that by definition of "override", only virtual functions can be "overridden".

Is overriding a method that has been overridden?

Overriding is done so that a child class can give its own implementation to a method which is already provided by the parent class. In this case the method in parent class is called overridden method and the method in child class is called overriding method.


2 Answers

If you are willing to change a few things, you can use the curiously recurring template pattern to determine if the function is overridden

#include <iostream>

template <class Derived>
struct Base
{
    virtual void on_event() {}

    void raise_event()
    {
        if (&Derived::on_event == &Base::on_event)
            std::cout << "not overridden" << std::endl;
        else
            std::cout << "overridden" << std::endl;
    }
};

struct Concrete1 : Base<Concrete1>
{
    virtual void on_event() override {}
};

struct Concrete2 : Base<Concrete2>
{
    // no override
};

int main()
{
    Concrete1 c1;
    Concrete2 c2;

    c1.raise_event(); // prints overridden
    c2.raise_event(); // prints not overridden

    return 0;
}

The statement &Derived::on_event == &Base::on_event should be resolved at compile-time (if that's what you're worried about) and the if can be optimized away.

Though I agree with others' opinions that this seems like a poor pattern. It would be much simpler to have the base class have empty event handlers like you already have.

like image 99
kmdreko Avatar answered Oct 11 '22 12:10

kmdreko


Don't use virtual methods at all. If all you want is given some concrete type, Concrete, to hook it up to a bunch of callbacks based on the presence of member functions then we can use templates.

For a given type and function name, we can determine if &T::func exists at compile time. If it does, we add that callback. So we end up with a whole bunch of things like:

template <class T>
void setup_cbs(T& object) {
    T* ptr_to_object = ...; // store somewhere

    static_if<has_on_event_foo<T>>(
        [](auto ptr){ 
            add_event_foo_callback(ptr, [](void* p, int i) {
                using U = decltype(ptr);
                static_cast<U>(p)->on_event_foo(i);
            })
        }),
        [](auto ){}
        )(ptr_to_object);

I'm assuming the callback adder takes a pointer and a callback. You will separately have to figure out how to store the pointers, but that seems easier.

like image 45
Barry Avatar answered Oct 11 '22 12:10

Barry