如果私有虚拟函数被覆盖为派生类中的公共函数,那么问题是什么

If a private virtual function is overridden as a public function in the derived class, what are the problems?

本文关键字:函数 问题是 问题 是什么 虚拟 覆盖 如果 派生      更新时间:2023-10-16
using namespace std;
#include <cstdio>
#include <iostream>
class One{
    private:
        virtual void func(){
            cout<<"bark!"<<endl;
        }
};
class Two: public One{
    public:
        void func(){
            cout<<"two!"<<endl;
        }
};
int main(){
    One *o = new Two();
    o->func();
}

为什么o->func()上有错误?

我不知道其背后的机制...我认为,o->func()应该在派生类中拨打func(),这是公开的,所以不会有问题,但它说:

 error: ‘virtual void One::func()’ is private

根据对象的静态类型执行可访问性检查。o的类型为One*。这意味着如果One::func()private,则o->func()不会编译。

另一方面,基于对象的动态类型,将调用虚拟成员函数(即动态调度)。因此,如果One::func()publico->func()将调用Two::func(),因为o指向类型Two的对象。

对于您的示例代码和用例,制作One::func() private只是毫无意义。但是请注意,有一个名为非虚拟界面的著名成语,它利用private基类的虚拟成员函数。


其他建议:

  1. 不要忘记delete o;
  2. 在基类One中添加虚拟破坏者。否则delete o;将导致不确定的行为;例如Two的破坏者可能不会被调用。

    class One {
        public:
            virtual ~One() {}
        // ...
    };
    

一个子类无法缓解继承限制,即使Func是虚拟的,它仍然是继承限制。

请参阅此答案,以获取有关继承限制的观点:

私人,公共和受保护的继承之间的区别

请检查访问说明器和虚拟函数。

来自标准:

§11.5[class.access.virt]虚拟的访问规则(第11条) 功能由其声明确定,不受 后来覆盖它的函数的规则。

使用表达式的类型在呼叫点检查访问 用于表示调用成员函数的对象。这 在定义的类中访问成员函数的函数是 一般来说。

如果名称查找确定可行函数为虚拟函数,则在用于命名函数的对象表达式的静态类型的范围内检查虚拟函数的访问说明符。在运行时,可以在派生类中定义要调用的实际函数,并具有完全不同的访问说明符。这是因为"访问说明符"是一种编译时间现象。

由于One *o的范围中检查了函数func()的访问说明符,并且在类One中是私有的,因此会产生错误。

如果Onefunc()声明为公共,并且Two将其私有化,则不会有任何错误。请参阅调用此私人功能并有效。你们中的任何一个都可以推荐它