公共虚函数在C++中派生为private

18 c++ inheritance virtual-functions

我试图找出当派生类将虚拟函数声明为私有时会发生什么.以下是我写的程序

#include <iostream>
using namespace std;
class A
{
    public:
        virtual void func() {
        cout<<"A::func called"<<endl;
    }
    private:
};
class B:public A
{
    public:
    B()
    {
        cout<<"B constructor called"<<endl;
    }
    private:
    void func() {
        cout<<"B::func called"<<endl;
    }
};
int main()
{
    A *a = new B();
    a->func();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是(对我来说)输出是:

B constructor called
B::func called
Run Code Online (Sandbox Code Playgroud)

这不是违反该功能的私人访问集.这是预期的行为吗?这是标准的解决方法还是漏洞?通过VTABLE解析函数调用时是否绕过了访问级别?

对此行为的任何了解都会非常有帮助.

此外,有人提到私有覆盖虚拟成员会阻止进一步的类继承它.即使这有问题.修改上述程序包括:

class C: public B
{
    public:
    void func() {
        cout<<"C::func called"<<endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

以及主要的测试程序:

int main()
{
    A *a = new C();
    a->func();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

C::func called
Run Code Online (Sandbox Code Playgroud)

rlb*_*ond 12

这是明确定义的行为.如果这a是一个B*不会编译.原因是成员访问由编译器静态解析,而不是在运行时动态解析.许多C++书籍都建议您避免使用这样的编码,因为它会让经验较少的编码人员感到困惑.

  • @Tom:在编译时检查程序的语义.您正在使用A*调用func(),这是一个有效的调用.comipler无法知道此调用是否在运行时解析为私有成员函数调用.在运行时,没有私有或公共的概念,它只是一个函数调用.如果您使用了B*而不是A*,则对func()的调用将无效,编译器会将其标记为错误. (4认同)

Sad*_*ido 11

行为是正确的.每当您将函数声明为"虚拟"时,都会指示编译器生成虚拟调用,而不是直接调用此函数.每当您覆盖后代类中的虚函数时,您都可以指定此函数的行为(您不会更改那些依赖于"父"接口的客户端的访问模式).

更改后代类中虚函数的访问模式意味着您要将其隐藏在直接使用后代类(依赖于"子"接口)的客户端中.

考虑这个例子:

void process(const A* object) {
   object->func();
}
Run Code Online (Sandbox Code Playgroud)

"process"函数依赖于父接口.它适用于任何类,公共派生自A.你不能公开从A派生B(说"每个B是A"),但隐藏其界面的一部分.那些期望"A"的人必须得到一个功能齐全的"A".