【问题标题】:std::bind()-ing a base protected member function from a derived class's member functionstd::bind() - 从派生类的成员函数中获取基类受保护的成员函数
【发布时间】:2013-01-08 16:16:32
【问题描述】:

我想bind() 到派生类中我的基类版本的函数。该功能在底座中标记为受保护。当我这样做时,代码在 Clang (Apple LLVM Compiler 4.1) 中顺利编译,但在 g++ 4.7.2 和 Visual Studio 2010 中都出现错误。错误类似于:“'Base::foo': cannot访问受保护的成员。”

这意味着引用的上下文实际上在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 );
    }
};

为什么会出现行为差异?哪个是对的?错误生成编译器有什么解决方法?

【问题讨论】:

  • Derived::foo 调用自己是故意的,还是只是简化为示例的结果?
  • @aschepler 这是“合法但不受欢迎”的“不受欢迎”部分。

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


【解决方案1】:

答案:参见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() {}
};

【讨论】:

  • 如果您无法更改Base,请使用派生方法(例如void basefoo(){ Base::foo(); })对其进行调整。在 Visual C++(Express 2010)中令人惊讶且令人困惑的是,您实际上可以使用 &amp;Derived::Base::foo 绕过此错误,但它基本上忽略了您的第二个参数(即,它始终使用 this)。
  • 替代方法,使用 lambda:auto fn = [=](Derived* d) { d-&gt;foo(); }; fn(this);
【解决方案2】:

这与bind 无关。由于已经引用了标准 @rhalbersma 的部分,&amp;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!
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2011-11-10
    • 2020-12-24
    相关资源
    最近更新 更多