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

Getting access-specifier error while calling virtual function of derived class which is private in base class

本文关键字:访问 错误 说明符 函数 基类 调用 派生      更新时间:2023-10-16

为什么我得到访问说明符错误(私有成员)为以下一段代码?

#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(),因为它是公共的,所以应该没有错误。

按标准(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
}

- 结束示例]

顺便说一句,一般情况下,在编译过程中不可能知道哪个类将在运行时被调用。

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

其中,GetBaseOrDerivedObject根据具体的运行情况,可以返回指向BaseDerived类型对象的指针。

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

遗憾的是,这不是真的。

如此:

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

这行不通:

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

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


存在一个众所周知的成语NVI (非虚接口),它主要基于此模式(基类中的私有虚成员方法)。您可以将其想象为模板方法模式的细化,尽管老实说这根本不是真的。