简体   繁体   中英

std::bind()-ing a base protected member function from a derived class's member function

I want to bind() to my base class's version of a function from the derived class. The function is marked protected in the base. When I do so, the code compiles happily in Clang (Apple LLVM Compiler 4.1) but gives an error in both g++ 4.7.2 and in Visual Studio 2010. The error is along the lines of: "'Base::foo' : cannot access protected member."

The implication is that the context for the reference is actually within bind() , where of course the function is seen as protected. But shouldn't bind() inherit the context of the calling function--in this case, Derived::foo() --and therefore see the base method as accessible?

The following program illustrates the issue.

struct Base
{
protected: virtual void foo() {}
};

struct Derived : public Base
{
protected:
    virtual void foo() override
    {
        Base::foo();                        // Legal

        auto fn = std::bind( &Derived::foo, 
            std::placeholders::_1 );        // Legal but unwanted.
        fn( this );

        auto fn2 = std::bind( &Base::foo, 
            std::placeholders::_1 );        // ILLEGAL in G++ 4.7.2 and VS2010.
        fn2( this );
    }
};

Why the discrepancy in behavior? Which is correct? What workaround is available for the error-giving compilers?

This has nothing to do with bind . Because of the piece of the Standard @rhalbersma already quoted, the expression &Base::foo is illegal in a non-friended member of Derived , in every context.

But if your intent was to do something equivalent to calling Base::foo(); , you have a bigger issue: pointers to member functions always invoke a virtual override.

#include <iostream>

class B {
public:
    virtual void f() { std::cout << "B::f" << std::endl; }
};

class D : public B {
public:
    virtual void f() { std::cout << "D::f" << std::endl; }
};

int main() {
    D d;
    d.B::f();   // Prints B::f

    void (B::*ptr)() = &B::f;
    (d.*ptr)(); // Prints D::f!
}

Answer: see boost::bind with protected members & context which quotes this part of the Standard

An additional access check beyond those described earlier in clause 11 is applied when a non-static data member or nonstatic member function is a protected member of its naming class (11.2)105) As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall name C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.

Workaround: make foo a public member function

#include <functional>

struct Base
{
public: virtual void foo() {}
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM