【问题标题】:Getting access-specifier error while calling virtual function of derived class which is private in base class调用基类中私有的派生类的虚函数时出现访问说明符错误
【发布时间】:2016-07-05 20:37:56
【问题描述】:

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

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

【问题讨论】:

    标签: c++


    【解决方案1】:

    按照标准(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 类型对象的指针。

    【讨论】:

    • 我真的没明白。根据后期解决方案,vptr 必须指向派生类的vtable。由于派生类fun() 是公共的,因此必须毫不费力地调用它。基类是如何出现在这里的?还是我对后期绑定的理解有误?
    • 检查是在编译时进行的,而不是在运行时进行的,所以与后期绑定无关。
    【解决方案2】:

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

    很遗憾,这不是真的。

    这行得通:

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

    这不起作用:

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

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


    有一个众所周知的成语称为NVI非虚拟接口),它主要基于这种模式(基类中的私有虚拟成员方法)。 你可以把它想象成对模板方法模式的改进,尽管说实话这根本不是真的。

    【讨论】:

      猜你喜欢
      • 2013-10-22
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      • 2018-05-11
      • 2017-04-13
      • 2021-11-10
      相关资源
      最近更新 更多