为什么这段代码无法编译?

3

我的情况是这样的:

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

它可以成功编译。这背后的逻辑是什么?


3
在第一种情况下尝试使用&::Foo::Barry - Kerrek SB
@MislavBlažević 从Foo中使用公共继承(或结构体的默认公共继承)。 - Peter L.
void Blah() { ::Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); }已修复 - Mislav Blažević
4个回答

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
问题在于,在Foo内或任何继承自它的类中,Foo是“注入类名”;这是一个在Foo内部范围内隐藏了相同名称于封闭命名空间中的名称。在这种情况下,由于私有继承,该名称无法访问。
您可以通过显式引用命名空间中的名称来解决此问题,在这种情况下为::Foo。不幸的是,如果您将类移动到另一个命名空间中,这将会中断。

0

这是一个名称冲突。对于每个继承的类型,您在自己的类中获得该名称的成员。要访问实际类型,您需要通过其限定名称引用它(在本例中为::Foo)。

此功能允许您从派生类中使用基类的隐藏或重写成员:

struct X
{
    void Foo();
};

struct Y : public X
{
    void Foo()
    {
        X::Foo(); // calls X's implementation of Foo
    }
};

但这意味着,如果你指的是struct X中的X,你需要用它的全名来限定它,即调用::X


这是一个私有继承与公共继承的问题,与命名冲突无关。 - Zac Howland
@ZacHowland,为什么使用::Foo而不是只用Foo会起作用?此外,我们在哪里使用了私有继承的成员? - zneak
那只能起作用,因为他正在创建第二个Foo实例来绑定。他正在使用“有一个”关系,然后使用组合创建另一个关系。 - Zac Howland
他试图在一个私有继承自Foo的类中调用_distinct_ Foo对象上的Foo方法,但是它不起作用,因为编译器认为他正在引用一个私有继承的成员。对我来说,这听起来非常像一个名称引用了两个不同的东西的情况。 - zneak
啊,我现在明白你的意思了。 - Zac Howland

-1

当你使用私有继承从Foo继承Bar时,你会使得所有Foo的成员数据/函数都变为私有。因此,当你从Bar继承Fooey时,它无法访问任何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对象(也就是说,通过继承Bar,Fooey已经有了一个Foo对象 - 这里创建了另一个并将其与Barry绑定)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接