2016-02-29 215 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'对象才能访问它的基类。 –