2016-02-29 149 views
1

我的問題是,爲什麼我不能把通過指針保護在派生類中虛函數的基類,除非聲明派生類的基類的朋友嗎?C++保護成員繼承

例如:

#include <iostream> 

class A { 
    friend class C; // (1) 
protected: 
    virtual void foo() const = 0; 
}; 

class B : public A { 
    void foo() const override { std::cout << "B::foo" << std::endl; } 
}; 

class C : public A { 
    friend void bar(const C &); 
public: 
    C(A *aa) : a(aa) { } 
private: 
    void foo() const override { 
    a->foo();  // (2) Compile Error if we comment out (1) 
    //this->foo(); // (3) Compile OK, but this is not virtual call, and will cause infinite recursion 
    std::cout << "C::foo" << std::endl; 
    } 
    A *a; 
}; 

void bar(const C &c) { 
    c.foo(); 
} 

int main() { 
    B b; 
    C c(&b); 
    bar(c); 

    return 0; 
} 

輸出是

B::foo 
C::foo 

在上面的代碼中,我想通過C類(的構件a調用虛函數foo()不是靜態綁定一個通this在編譯時),但如果我不作CA的朋友,電話是違法的。

我認爲CA繼承的,所以它可以訪問的Aprotected成員,但爲什麼它實際上不會發生呢?

+0

那麼,在技術上,'A-> FOO();'不是虛擬呼叫任一。要在你的基類中調用'foo'方法,可以這樣調用它:'A :: foo();'。 –

+0

@AlgirdasPreidžius通過指向基類的指針調用不是虛擬調用?此外,'A :: foo'是沒有定義一個純虛函數,我覺得像'A.A :: foo'通話是在編譯時的約束,將是這種情況的一個錯誤。 – Jaege

+0

@AlgirdasPreidžius否,如OP表明,'A-> FOO()的結果是''B :: foo'。 – songyuanyao

回答

5

C可以訪問自己的基類的保護成員,但不是任何其他A成員。

在您的示例中,參數a是完全無關的類B的一部分,其中C沒有訪問權限(除非您將其設爲朋友)。

+0

感謝您的回答。但是我仍然有一個疑問:根據標準,虛擬函數的訪問級別由其基類中的聲明決定。所以編譯器在編譯時不會知道參數'a'是類'B'的一個對象的一部分。我應該如何理解這個問題? – Jaege

+0

實際上,如果'a'參數恰好是其他'C'對象的一部分,這並不重要。編譯器無法判斷它是否得到一個指向「A」的指針。它必須有一個已知的'C'對象才能訪問它的基類。 –