我试图找出派生类将虚拟函数声明为私有时会发生什么。以下是我写的程序
#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
答案 0 :(得分:12)
这是明确定义的行为。如果a
是B*
,则无法编译。原因是成员访问由编译器静态解析,而不是在运行时动态解析。许多C ++书籍都建议您避免使用这样的编码,因为它会让经验较少的编码人员感到困惑。
答案 1 :(得分:11)
行为是正确的。每当您将函数声明为“虚拟”时,都会指示编译器生成虚拟调用,而不是直接调用此函数。每当您覆盖后代类中的虚函数时,您都可以指定此函数的行为(您不会更改那些依赖“父”接口的客户端的访问模式)。
更改后代类中虚拟函数的访问模式意味着您要将其隐藏在那些直接使用后代类(依赖于“子”接口)的客户端中。
考虑一下这个例子:
void process(const A* object) {
object->func();
}
“process”函数依赖于父级的接口。它可以用于任何类,公共派生自A.你不能公开从A派生B(说“每个B是A”),但隐藏其界面的一部分。那些期望“A”的人必须得到一个功能齐全的“A”。
答案 2 :(得分:3)
嗯,您呼叫的A::func()
public
虽然在B
对象中被B::func()
覆盖。这是一种具有以下含义的常见模式:
func
无意在派生的B
对象上调用
func
无法在从B