Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding to privately inherited member function

I'd like to std::bind to a member function from a private base class, made "public" with a using-declaration in the derived class. Calling the function directly works, but it seems binding or using member function pointers doesn't compile:

#include <functional>

struct Base {
    void foo() { }
};

struct Derived : private Base { 
    using Base::foo;            
};

int main(int, char **)
{
    Derived d;

    // call member function directly:
    // compiles fine
    d.foo();

    // call function object bound to member function:
    // no matching function for call to object of type '__bind<void (Base::*)(), Derived &>'
    std::bind(&Derived::foo, d)();

    // call via pointer to member function:
    // cannot cast 'Derived' to its private base class 'Base'
    (d.*(&Derived::foo))();

    return 0;
}

Looking at the error messages above, the issue seems to be that Derived::foo is still just Base::foo, and I can't access Base through Derived outside Derived itself.

This seems inconsistent - should I not be able to use direct calls, bound functions, and function pointers interchangeably?

Is there a workaround that would let me bind to foo on a Derived object, preferably without changing Base or Derived (which are in a library I don't own)?

like image 252
Anders Johansson Avatar asked Mar 28 '16 13:03

Anders Johansson


People also ask

Can a private member of a class be inherited by a derivative?

A private member of a class cannot be inherited and, as a result, is not available for the derivative class directly. What happens if private data is to be inherited by a derived class? C++ provides a third, protected, visibility modifier for restricted inheritance use.

What is private inheritance in Java?

Now, in Private inheritance, the public and protected members of the base class become private members of the derived class the private members of the base class cannot be accessed by the derived class.

Can we use the private members of base class in derived class?

the private members of the base class cannot be accessed by the derived class. the interface of the base class is not being inherited but its implementation is being inherited which means one can use the contents of the base class as it is using the member functions of the derived class. Let us consider a class for better understanding:

What is public protected and private inheritance in C++?

public, protected and private inheritance in C++ public, protected, and private inheritance have the following features: public inheritance makes public members of the base class public in the derived class, and the protected members of the base class remain protected in the derived class.


1 Answers

The issue here is what the using-declaration actually does:

struct Derived : private Base { 
    using Base::foo;            
};

That brings Base::foo into public scope in Derived, but it doesn't create an entirely new function. It is not equivalent to having written:

struct Derived : private Base {
    void foo() { Base::foo(); }
}

There is still only Base::foo(). The using-declaration simply affects the access rules and the overload resolution rules. As such &Derived::foo really has type void (Base::*)() (and not void (Derived::*)()!), since that is the only foo that exists. Since Base is private, member access through a pointer to Base is ill-formed. I agree that this is pretty unfortunate ("inconsistent" is a good word).

You can still create a function object that calls foo. You just can't use the pointer to member. With C++14, this becomes straightforward if verbose (I'm assuming arbitrary arguments here and that void foo() is merely a simplification of the problem):

auto d_foo = [d](auto&&... args){ return d.foo(std::forward<decltype(args)>(args)...); }

With C++11, you'd have to write a type with a variadic template operator().

like image 165
Barry Avatar answered Oct 06 '22 22:10

Barry