2013-08-22 287 views
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'。 –

+0

就是這樣!謝謝! –

+0

@MislavBlažević使用來自Foo的公共繼承(或默認的公共結構)。 –

回答

7

這裏

struct Fooey : public Bar 
{ 
    void Blah() { Foo f; Bar::Bleh(std::bind(&Foo::Barry, &f)); } 
}; 

Foo名稱查找發現的基類的Bar這是因爲inaccesible繼承Bar私自。

爲了解決這個問題,完全限定名稱:

void Blah() { ::Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); } 
0

這是一個名稱衝突。對於每個繼承類型,您都會在自己的類中獲得該名稱的成員。要訪問實際的類型,您需要通過其合格的名稱來引用它(在此例中爲::Foo)。

此功能可讓您使用一個基類的陰影或重寫成員派生類:

struct X 
{ 
    void Foo(); 
}; 

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

但它確實意味着,如果你的意思是Xstruct X,你需要充分出線它名稱,稱之爲::X

+0

這是一個私人與公共繼承問題,與命名衝突無關 –

+0

@ZacHowland,那麼怎麼用' :: Foo'而不只是'Foo'有效嗎?此外,我們在哪裏使用一個私人繼承的成員? – zneak

+0

這隻適用於因爲他正在創建第二個「Foo」綁定。他正在使用「有一個「關係,然後創建另一個使用合成 –

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

該塊,其中包含的範圍「修復」也創造了另一個Foo(即Fooey已經通過其繼承一個Foo對象與Bar - 這正在創造另一個並且約束它的Barry)。

1

問題是,在Foo或其派生的任何類別中,Foo注入的類名稱;名稱範圍在Foo之內,該名稱隱藏了封閉名稱空間中該類的相同名稱。在這種情況下,由於私有繼承而無法訪問。

您可以通過顯式引用名稱空間中的名稱(在本例中爲::Foo)來解決此問題。不幸的是,如果您將該類移入另一個名稱空間,那將會中斷。