2013-01-24 44 views
10

我想bind()從派生類的基類的函數版本。該功能在底座中被標記爲受保護。當我這樣做的時候,代碼在Clang(Apple LLVM Compiler 4.1)中編譯得很愉快,但是在g ++ 4.7.2和Visual Studio 2010中都出現了一個錯誤。錯誤是:''Base :: foo':can not訪問受保護的成員「。std :: bind() - 來自派生類的成員函數的基本保護成員函數

含義是引用的上下文實際上在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); 
    } 
}; 

爲什麼行爲上的差異?哪個是對的?解決錯誤的編譯器有哪些解決方法?

+0

「Derived :: foo」本身是故意的,還是僅僅是簡化爲例的結果? – aschepler

+0

@aschepler這是「合法但不需要」的「不需要」部分。 – OldPeculier

回答

9

答案:看到boost::bind with protected members & context它引用的標準

該部分超出在第11 前面描述的附加的訪問檢查時應用一個非靜態數據成員或非靜態成員函數 是被保護的(11.2)105)如之前描述的 ,由於參考 發生在朋友或某個類C的成員中,所以准予訪問受保護的成員。如果訪問形成 ,則指向成員(5.3 .1),嵌套名稱說明符應將C或 ac所有其他訪問涉及(可能爲 隱式)對象表達式(5.2.5)。在這種情況下,類 對象表達的應是C或從C

衍生

解決方法的類:使foo一個public成員函數

#include <functional> 

struct Base 
{ 
public: virtual void foo() {} 
}; 
+3

如果你不能改變'Base',用Derived方法修改它(例如'void basefoo(){Base :: foo();}')。在Visual C++(Express 2010)中令人驚訝和困惑的是,你實際上可以使用&Derived :: Base :: foo來繞過這個錯誤,但它基本上忽略了你的第二個參數(即它總是使用'this')。 –

9

這具有無關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! 
} 
相關問題