调用派生类的虚函数时获取访问说明符错误,派生类在基类中是私有的

时间:2016-07-05 20:37:57

标签: c++

为什么我要为以下代码获取访问说明符错误(私有成员)?

#include<iostream>
using namespace std;

class Derived;

class Base {
private:
    virtual void fun() { cout << "Base Fun"; }
};

class Derived: public Base {
public:
    void fun() { cout << "Derived Fun"; } //this should be called
};

int main()
{
   Base *ptr = new Derived;
   ptr->fun();
   return 0;
}

这里,应该调用派生类的fun(),因为它是公共的,所以不应该有错误。

2 个答案:

答案 0 :(得分:5)

根据标准(N4140):

  

11.5访问虚拟功能

     

1 虚函数的访问规则(第11条)由其声明决定,不受影响   稍后覆盖它的函数的规则。 [示例

class B {
public:
    virtual int f();
};
class D : public B {
private:
    int f();
};
void f() {
    D d;
    B* pb = &d;
    D* pd = &d;
    pb->f(); // OK: B::f() is public,
             // D::f() is invoked
    pd->f(); // error: D::f() is private
}
     

- 结束示例]

BTW,一般情况下,在编译期间无法知道在运行时调用哪个类。

考虑

Base *ptr = GetBaseOrDerivedObject();
ptr->fun();

其中GetBaseOrDerivedObject,根据具体的运行时情况,可以将一个poiner返回到BaseDerived类型的对象。

答案 1 :(得分:0)

  

这里应该调用派生类的fun(),因为它是公共的,所以不应该有错误。

不幸的是,事实并非如此。

这有效:

 Derived *ptr = new Derived;
 ptr->fun();

这不起作用:

 Base *ptr = new Derived;
 ptr->fun();

原因很简单:Base没有名为fun的公开成员,因此您无法通过指向Base的指针访问它。 您可以在派生类中为重写的成员方法设置自己的可见性说明符,但这不会神奇地提升基类的说明符。

有一个众所周知的成语叫做 NVI 非虚拟接口),它主要基于这种模式(基类中的私有虚拟成员方法)。登记/> 您可以将其想象为模板方法模式的改进,即使说实话,这根本不是真的。