cwbusacker
cwbusacker

Reputation: 517

How to send a pointer of an overriden virtual function to the base class?

An example:

class Base
{
    protected:
        virtual void function() { std::cout << "Base\n"; }
        void callfunction(void (Base::* func)()) { (this->*func)(); }
};

class Derived1 : public Base
{
    public:
        void publicCall() { callfunction(&Derived1::function); }
    private:
        void function() override { std::cout << "Derived1\n"; }
};

I would like to be able to send the derived function pointer to the base class to fulfill a pattern that can be specified in the base class. Thus, reusing code.

However, I'm not sure what the type is supposed to be in the base class since Base::* is not a Derived1::*.

I get the following error: No instance of overloaded function callfunction matches the argument list: arguments types are (Derived1::*)

Now obviously, I could change the data type to be Derived1::*, but that wouldn't allow me to send in other derived class virtual functions back to Base to handle, such as Derived2::function()

Can a template sort of function be created like this?

Upvotes: 3

Views: 450

Answers (5)

user5550963
user5550963

Reputation:

Use std::function<> instead of C style function pointer.

std::function<returnType (parameterType)> functionPointer = functionName;

Do not forget to include <functional>.

I think this will resolve your problem, but for sure it is preferred.

To pass it directly:

void callfunciton(const std::function<void()>& func);

and call by

callfunction([]{ function(); });

EDIT: Read this to learn why you should use std::function<>.

Upvotes: 2

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

Just send &Base::function. Since it's virtual, the right one will be called.

The only problem here is that Base::function is protected and you cannot access it from Derived (strange but true). OTOH &Derived::function won't convert to void (Base::* func)() (and for a good reason). So you have to either make Base::function public, or provide an accessor:

class Base { 
  ...
  protected:
    auto getFunction() { return &Base::function; }

Live demo

Upvotes: 2

Justin
Justin

Reputation: 25327

You can cast the member function pointer to the base class member function pointer type: callfunction(static_cast<void (Base::*)()>(&Derived1::function));. Full example:

class Base
{
    protected:
        virtual void function() { std::cout << "Base\n"; }
        void callfunction(void (Base::* func)()) { (this->*func)(); }
};

class Derived1 : public Base
{
    public:
        void publicCall() { callfunction(static_cast<void (Base::*)()>(&Derived1::function)); }
    private:
        void function() override { std::cout << "Derived1\n"; }
};

This is allowed; see cppreference on pointers to member functions:

Pointer to member function of a base class can be implicitly converted to pointer to the same member function of a derived class ...
Conversion in the opposite direction, from a pointer to member function of a derived class to a pointer to member function of an unambiguous non-virtual base class, is allowed with static_cast and explicit cast

In this case, we are converting derived to base rather than vice-versa, so we need to static_cast.


You can avoid requiring the cast from the call-site by casting in Base from a template:

class Base
{
    protected:
        virtual void function() { std::cout << "Base\n"; }
        void callfunction(void (Base::* func)()) { (this->*func)(); }

        template <typename Derived, std::enable_if_t<std::is_convertible_v<Derived const*, Base const*>, int> = 0>
        void callfunction(void (Derived::* func)()) { callfunction(static_cast<void (Base::*)()>(func)); }
};

class Derived1 : public Base
{
    public:
        void publicCall() { callfunction(&Derived1::function); }
    private:
        void function() override { std::cout << "Derived1\n"; }
};

Compiler Explorer link: https://godbolt.org/z/3x8qPK4Tf

Upvotes: 1

gallo magico
gallo magico

Reputation: 68

I think that a template function should work

template<class _DType>
void Base::callFunction(void(_DType::*func)()) { func(); }

then the function from Derived1

void Derived1::publicCall() { Base::callFunction(&Derived1::function); }

This work as long as Derived1 is derived by Base, that is not what you wrote but I'm assuming you just missed, anyway next time I would add class Derived1: public Base to have a more clear code.

Upvotes: 1

Chris Uzdavinis
Chris Uzdavinis

Reputation: 6131

Your question is asking for CRTP, a poorly named but well known label for the idiom described in a 1995 article by Jim Coplien, titled "A Curiously Recurring Template Pattern". The idea is well documented, so I won't go into depth, but the idea is pretty simple: The base class takes a template argument, and the derived class provides its type to the base. Then the base class can "downcast" the this pointer to the derived type and call the function without needing a virtual call.

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

What is the curiously recurring template pattern (CRTP)?

Upvotes: 1

Related Questions