为什么我要为以下代码获取访问说明符错误(私有成员)?
#include<iostream>
using namespace std;
class Derived;
class Base {
private:
virtual void fun() { cout << "Base Fun"; }
};
class Derived: public Base {
public:
void fun() { cout << "Derived Fun"; } //this should be called
};
int main()
{
Base *ptr = new Derived;
ptr->fun();
return 0;
}
这里,应该调用派生类的fun()
,因为它是公共的,所以不应该有错误。
答案 0 :(得分:5)
根据标准(N4140
):
BTW,一般情况下,在编译期间无法知道在运行时调用哪个类。11.5访问虚拟功能
1 虚函数的访问规则(第11条)由其声明决定,不受影响 稍后覆盖它的函数的规则。 [示例:
class B { public: virtual int f(); }; class D : public B { private: int f(); }; void f() { D d; B* pb = &d; D* pd = &d; pb->f(); // OK: B::f() is public, // D::f() is invoked pd->f(); // error: D::f() is private }
- 结束示例]
考虑
Base *ptr = GetBaseOrDerivedObject();
ptr->fun();
其中GetBaseOrDerivedObject
,根据具体的运行时情况,可以将一个poiner返回到Base
或Derived
类型的对象。
答案 1 :(得分:0)
这里应该调用派生类的fun(),因为它是公共的,所以不应该有错误。
不幸的是,事实并非如此。
这有效:
Derived *ptr = new Derived;
ptr->fun();
这不起作用:
Base *ptr = new Derived;
ptr->fun();
原因很简单:Base
没有名为fun
的公开成员,因此您无法通过指向Base
的指针访问它。
您可以在派生类中为重写的成员方法设置自己的可见性说明符,但这不会神奇地提升基类的说明符。
有一个众所周知的成语叫做 NVI (非虚拟接口),它主要基于这种模式(基类中的私有虚拟成员方法)。登记/> 您可以将其想象为模板方法模式的改进,即使说实话,这根本不是真的。