2015-02-11 50 views
25

看一看下面的代碼:using聲明在派生類中絲毫不掩飾從基類派生的功能相同

struct A { 
public: 
    virtual void f(){std::cout << "in A";}; 
}; 

struct B : A{ 
public: 
    virtual void f(){std::cout << "in B";}; 
    int a; 
}; 

struct C : B{ 
    using A::f; 
    void test(){f();} 
}; 


int main() 
{ 
    C c; 
    c.f(); // calls B::f, the final overrider 
    c.C::f(); // calls A::f because of the using-declaration 
    c.test(); //calls B::f 
    return 0; 
} 

按我的理解,在CB::f()應隱藏其被帶到CA::f()通過使用聲明;如果是這樣,那爲什麼c.C::f()仍然叫A::f()

如果c.C::f()電話A::f(),這應該意味着在C範圍,f()應始終參考A::f(),這是使用聲明的功能。那麼爲什麼在C::test(),撥打f()仍然評估爲B::f()

回答

29

非常好的問題,一個複雜的名稱查找案例。

基本上,當名fC範圍擡起頭,它總是發現由於A::f的使用聲明。因此,在C::test()中的所有調用c.f(),c.C::f()f(),將名稱f解析爲A::f

接下來是虛擬調度。如果一個虛擬函數被一個非限定名稱調用,動態調度發生,並且最終的覆蓋被調用。這包括c.f()和中的f()調用,因爲這些不合格。

呼叫c.C::f()使用f的限定名稱,該名稱禁止動態分派以及直接調用解析名稱的函數。由於該功能是A::f(感謝使用聲明),因此A::f被稱爲非虛擬。有關規則遵循(引用C++ 14 N4140最後草案,重點煤礦):

10.3節/ 15

顯式資格與範圍操作者(5.1)抑制虛擬調用機制。

§5.2.2/ 1

...如果所選擇的功能是非虛擬,或者如果在類成員訪問表達 ID-表達是一個qualified-id,該函數被調用。否則,調用其在對象表達式的動態類型中的最終覆蓋(10.3)的 ;這樣的呼叫被稱爲虛擬功能調用的

+0

@LiuNick新增。 – Angew 2015-02-11 09:55:59

+0

只是如此專業!謝謝! – 2015-02-11 09:59:28

+0

@LiuNick堆棧溢出說「謝謝」的方式是[接受解決問題的答案](http://stackoverflow.com/help/someone-answers)(每個問題最多隻能接受一個答案)。這標誌着問題已經解決,並給予回答者和你一些聲望。 – Angew 2015-02-11 10:05:00