std :: bind() - 从派生类的成员函数中获取基本受保护的成员函数

时间:2013-01-24 19:35:43

标签: c++ c++11 protected derived-class stdbind

我希望从派生类中bind()到我的基类的函数版本。该功能在基础中标记为受保护。当我这样做时,代码在Clang(Apple LLVM编译器4.1)中快速编译,但在g ++ 4.7.2和Visual Studio 2010中都出错。错误是:“'Base :: foo':不能访问受保护的成员。“

这意味着引用的上下文实际上在bind()内,当然这个函数被视为受保护。但是bind()不应该继承调用函数的上下文 - 在本例中为Derived::foo() - 因此将基本方法视为可访问的?

以下程序说明了这个问题。

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

为什么行为上存在差异?哪个是对的?错误提供编译器有哪些可用的解决方法?

2 个答案:

答案 0 :(得分:10)

这与bind无关。由于标准@rhalbersma的部分已被引用,因此&Base::foo表达式在Derived的非友好成员中是非法的。

但是如果你的意图是做一些等同于调用Base::foo();的事情,你就会遇到更大的问题:指向成员函数的指针总是调用虚拟覆盖。

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

答案 1 :(得分:9)

答案:请参阅引用标准

部分的boost::bind with protected members & context
  

除了第11章中所述之外的其他访问检查   在非静态数据成员或非静态成员函数时应用   是其命名类的受保护成员(11.2)105)如上所述   之前,因为引用而授予对受保护成员的访问权限   发生在朋友或某些C类的成员中。如果要形成   指向成员(5.3.1)的指针,嵌套名称说明符应命名为C或   从C派生的类。所有其他访问涉及(可能   隐式)对象表达式(5.2.5)。在这种情况下,类   对象表达式应为C或从C派生的类。

解决方法:使foo成为public成员函数

#include <functional>

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