2012-08-22 58 views
3

考慮做:爲什麼使用聲明沒有公開成員指針

struct foo 
{ 
    void foobar(){} 
}; 

struct bar : protected foo 
{ 
    using foo::foobar; 
}; 

int main() 
{ 
    bar b; 
    b.foobar(); // Fine 
    &bar::foobar; // Not fine 
} 

我不知道是什麼理由使用聲明揭露成員出租,而不是一個指針。實際上,它似乎全部使用聲明來改變訪問級別,除了獲取一個暴露函數的地址外,其他所有內容都適用。

UPDATE:它類似於我的實際使用情況較好的一個例子:

#include "boost/bind.hpp" 

struct foo 
{ 
    void foobar() {} 
}; 

struct bar : protected foo 
{ 
    using foo::foobar; 
    bar() { boost::bind(&bar::foobar, this)(); } // Crashes VS2008, GCC 4.1.1 fails to compile as it tries to go through foo* 
}; 

int main() 
{ 
    bar b; 
} 

然而,邁克Seymours'的解釋是現貨上,並解釋了爲什麼GCC失敗。謝謝!

+4

確定嗎? http://ideone.com/HbRik –

+0

@PaulManta - 可能只是VS2008然後,會做一些進一步的調查。 – Ylisar

+1

也許你可以提到你在問題的主體中使用了哪個編譯器?除了提供信息外,它還能讓我刪除我的downvote。 – juanchopanza

回答

6

[我假設在你的程序中的代碼是:void (bar::*p)() = &bar::foobar;]

的問題不在於使用聲明不帶標識送入太空,但&bar::foobar語義。我正在考慮(如果我有時間,我會這樣做)用這個補充缺陷報告。已經有一個這樣的報告。

基本上問題在於使用聲明將基本函數帶入派生類型中的查找範圍,並且將根據bar檢查表達式&bar::foobar的訪問說明符。 但是,表達式&bar::foobar的結果是void (foo::*)()類型,而不是void (bar::*)()。現在,&bar::foobar評估後,如果您嘗試使用它作爲void (bar::*)()編譯器將嘗試執行指針轉化爲成員,但會失敗,因爲foobar一個protected基地,並在main情況下你不有機會獲得這種關係。

請注意,由於兩個原因,我認爲這是一種語言缺陷:首先它會破壞您的代碼:void (bar::*p)() = &bar::foobar;令人驚訝地無法編譯。其次,它打破在其他情況下訪問保護:

這個問題實際上是對稱你的,而在你的令人驚訝的類型成員地址的最運行的抑制你的使用情況,當它不應該,在這種情況下,它允許違反protected意圖的用法。

相關鏈接:


使用bind的評論後,它可能不是你嘗試指針轉換爲成員的情況下直接指向bar的成員,但在bind代碼內的某處會生成代碼將指向成員的指針應用於bar的實例,並且需要進行轉換。

3

注:本回答了原來的問題;大衛羅德里格斯已經回答了更新。

你的代碼是正確的。根據語言標準:

7.3.3/2每使用聲明聲明成員聲明

這意味着你正在申報foobar是一個bar以及foo的成員,因此將其稱爲bar::foobarfoo::foobar一樣合法。

我的編譯器(GCC)同意這一點;如果你的不是,那麼它似乎有一個錯誤。

+2

我想他錯誤地從問題中刪除了一點。 void(bar :: * p)()=&bar :: foobar;'不會編譯。 –

+0

nitpick:使用聲明是類x中的成員聲明不會聲明類x的成員。 –