Old*_*ier 11 c++ protected derived-class stdbind c++11
我想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 );
}
};
Run Code Online (Sandbox Code Playgroud)
为什么行为上的差异?哪个是对的?错误提供编译器有哪些可用的解决方法?
asc*_*ler 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!
}
Run Code Online (Sandbox Code Playgroud)
答案:请参阅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() {}
};
Run Code Online (Sandbox Code Playgroud)