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

落爺英雄遲暮 提交于 2019-12-01 14:21:21

问题


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?


回答1:


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() {}
};



回答2:


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!
}


来源:https://stackoverflow.com/questions/14509291/stdbind-ing-a-base-protected-member-function-from-a-derived-classs-member-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!