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
答案 0 :(得分:13)
基于对象的静态类型执行辅助功能检查。 o
的类型为One*
。这意味着如果One::func()
为private
,那么o->func()
将无法编译。
另一方面,基于对象的动态类型,将在运行时调用哪个虚拟成员函数(即动态调度)。因此,如果One::func()
为public
,则o->func()
会调用Two::func()
,因为o
指向Two
类型的对象。
对于您的示例代码和用例,制作One::func()
private
毫无意义。但请注意,有一个名为Non-Virtual Interface的着名成语,它使用基类的private
虚拟成员函数。
其他建议:
delete o;
在基类One
中添加虚拟析构函数。否则delete o;
将导致未定义的行为;例如<{1}}的析构函数可能不会被调用。
Two
答案 1 :(得分:1)
子类无法简化继承限制, 即使func是虚拟的,它仍然是继承限制。
请参阅此答案以了解继承限制的相关视图:
Difference between private, public, and protected inheritance
答案 2 :(得分:1)
请检查Access specifiers and virtual functions。
从标准:
§11.5[class.access.virt]虚拟的访问规则(第11条) 功能由其声明决定,不受影响 稍后覆盖它的函数的规则。
使用表达式的类型在呼叫点检查访问 用于表示调用成员函数的对象。该 在定义它的类中访问成员函数 一般不知道。
如果名称查找将可行函数确定为虚函数,则在用于命名函数的对象表达式的静态类型范围内检查虚函数的访问说明符。在运行时,可以使用完全不同的访问说明符在派生类中定义要调用的实际函数。这是因为“访问说明符”是编译时现象。
由于在func()
范围内检查了函数One *o
的访问说明符,并且它在类One
中是私有的,因此会产生错误。
如果One
将func()
声明为公开,Two
将其声明为私有,则不会出现任何错误。见Private function invoked and it works. Could any of you reason it please