我遇到这样的情况:
struct Foo
{
void Barry() { }
};
struct Bar : private Foo
{
template <class F> void Bleh(F Func) { Func(); }
};
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&Foo::Barry, &f)); }
};
它不编译(g ++ 4.7.3)。有错误:
test.cpp: In member function ‘void Fooey::Blah()’:
test.cpp:4:1: error: ‘struct Foo Foo::Foo’ is inaccessible
test.cpp:15:23: error: within this context
test.cpp:4:1: error: ‘struct Foo Foo::Foo’ is inaccessible
test.cpp:15:47: error: within this context
但是,如果我这样做:
class Fooey;
void DoStuff(Fooey* pThis);
struct Fooey : public Bar
{
void Blah() { DoStuff(this); }
};
void DoStuff(Fooey* pThis)
{
Foo f;
pThis->Bleh(std::bind(&Foo::Barry, &f));
}
它编译得很好。这背后的逻辑是什么?
答案 0 :(得分:7)
下面
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&Foo::Barry, &f)); }
};
Foo
的名称查找查找Bar
的基类,因为Bar
私下继承而无法访问。
要修复它,请完全限定名称:
void Blah() { ::Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); }
答案 1 :(得分:1)
问题是,在Foo
或从中派生的任何类中,Foo
是注入的类名;一个作用于Foo
内部的名称,它在封闭名称空间中为该类隐藏相同的名称。在这种情况下,由于私有继承,这是不可访问的。
您可以通过明确引用命名空间中的名称来解决此问题,在本例中为::Foo
。不幸的是,如果将类移动到另一个名称空间,那将会中断。
答案 2 :(得分:0)
这是一个名称冲突。对于每个继承的类型,您将在自己的类中获得该名称的成员。要访问实际类型,您需要通过其限定名称(在本例中为::Foo
)引用它。
此功能允许您使用派生类的基类的带阴影或重写成员:
struct X
{
void Foo();
};
struct Y : public X
{
void Foo()
{
X::Foo(); // calls X's implementation of Foo
}
};
但这确实意味着,如果您的意思是X
与struct X
一样,则需要使用其全名对其进行限定,并将其命名为::X
。
答案 3 :(得分:-1)
当您使用私有继承从Bar
继承Foo
时,您将所有Foo
的成员数据/函数设为私有。因此,当您从Fooey
继承Bar
时,它无法访问任何Foo
的成员。
有关私有继承的更多详细信息:http://www.parashift.com/c++-faq/access-rules-with-priv-inherit.html
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); }
};
这个包含范围“fix”的块也会创建另一个Foo
(也就是说,Fooey已经通过Foo
继承了Bar
对象 - 这就创建了另一个并绑定其Barry
)。