我试图找出当派生类将虚拟函数声明为私有时会发生什么 . 以下是我写的程序
#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;
}
令人惊讶的是(对我而言)输出是:
B constructor called
B::func called
这不是违反该功能的私人访问集 . 这是预期的行为吗?这是标准的解决方法还是漏洞?通过VTABLE解析函数调用时是否绕过了访问级别?
对此行为的任何了解都会非常有帮助 .
此外,有人提到私有覆盖虚拟成员会阻止进一步的类继承它 . 即使这有问题 . 修改上述程序包括:
class C: public B
{
public:
void func() {
cout<<"C::func called"<<endl;
}
};
以及主要的测试程序:
int main()
{
A *a = new C();
a->func();
return 0;
}
输出是:
C::func called
3 回答
这是明确定义的行为 . 如果
a
是B*
,则无法编译 . 原因是成员访问由编译器静态解析,而不是在运行时动态解析 . 许多C书建议你避免这样编码,因为它会让经验较少的编码人员感到困惑 .好吧,你正在调用
A::func()
这是public
虽然在B
对象中它被B::func()
覆盖 . 这是一种常见的模式,具有以下含义:func
不应在派生的B
对象上调用func不能在从B派生的类中重写
行为是正确的 . 每当您将函数声明为“虚拟”时,都会指示编译器生成虚拟调用,而不是直接调用此函数 . 每当您覆盖后代类中的虚函数时,您都可以指定此函数的行为(您不会更改那些依赖于“父”接口的客户端的访问模式) .
更改后代类中虚函数的访问模式意味着您要将其隐藏在直接使用后代类(依赖于“子”接口)的客户端中 .
考虑这个例子:
“process”函数依赖于父级的接口 . 它适用于任何来自A的公共派生类 . 你不能从A公开派生B(说“每个B都是A”),但隐藏其界面的一部分 . 那些期望“A”的人必须得到一个功能齐全的“A” .