基类public虚函数在派生类被重写为private仍然可以调用!

maliang351 2014-01-10 09:53:40
在基类中定义了public虚函数,在派生类中将其重写,但是设置为private,为什么通过基类指针仍然可以发生动态绑定调用派生类中的private虚函数?
class Base
{
public:
// public虚函数
virtual void Disp() { cout << "base.\n"; }
};

class Derived : public Base
{
private:
// 重写基类虚函数,但是放在private中
virtual void Disp() { cout << "derived.\n"; }
};

void main()
{
Derived Dobj;
Base *pBase = &Dobj;
pBase->Disp(); // 显示的结果是派生类的虚函数被调用!
}


通过基类指针仍然正确的调用了虚函数。
这里,我的理解是:对于虚函数的动态调用,是与派生类的访问权限无关,其权限是由基类决定的。
因为C++编译器调用函数时,是
1)从静态类型(变量定义的类型)开始查找函数名,
2)找到了函数名之后,检查类型是否匹配(形参和返回值),
3)如果正确则该函数调用的合法,进而编译器生成代码调用函数。如果这个函数是虚函数且通过指针或引用调用,则根据其实际类型确定运行哪个函数版本,否则直接调用函数。
不知道这样理解是否正确,但不管怎么样,还是运行了派生类的private虚函数,感觉很诧异,希望大神们指点一二。
...全文
157 2 收藏 8
写回复
8 条回复
hzm7512 2014年01月10日
参见这个帖子: http://bbs.csdn.net/topics/210042197
回复 点赞
孩皮妞野 2014年01月10日
楼主的问题似乎有两个部分,一个居然可以调用,第二个而且调用的是派生类的。
回复 点赞
maliang351 2014年01月10日
恩,谢谢大家,学到了不少东西。 4楼的解释还是很犀利的。 派生类中虚函数的访问权限是在编译阶段由基类确定的,在运行阶段不再检查访问权限,所有,虚函数的访问权限与派生类就没关系了。
回复 点赞
飞天御剑流 2014年01月10日
这个问题与多态实现机制无关,试图从虚表角度去解析的行为不过是自我形成的错觉。 真正也是唯一的原因是:可访问性是静态解析的,不是动态解析的。即是说,无论最终覆盖者的可访问性如何,可访问性均取决于函数调用后缀表达式的可访问性。
回复 点赞
孩皮妞野 2014年01月10日
你的情形,当你pBase->Disp()时,首先通过这个对象的vptr找到对应的vtable, 因为它实际上是Derived对象,所以找到的是Derived的虚表,进程正所有的Derived对象都共用这个虚表。然后编译器从Base的类型信息中查到Disp是虚表中的第一个entry, 而且这个函数的访问权限是public的,所以首先它让你调用,其次,从虚表第一个entry中取出的函数地址对应着Derived::Disp, 所以最后是Derived::Disp被调用,Derived::Disp在Derived中的访问权限在这里是无关的了,编译器根本不会费事去查询这一信息。甚至这一信息可能根本编译器也不知道。
回复 点赞
derekrose 2014年01月10日
冲突来自于访问权限是在编译时刻确定的,而动态绑定在运行时确定
回复 点赞
孩皮妞野 2014年01月10日
虚函数是通过虚表来实现的。虚表可以理解为一个函数指针数组,编译器会根据函数名称和原型找到对应函数在虚表中的index. 派生类可能override了基类的实现,这样只是虚表中的函数指针变了,索引并没变。又因为是通过基类的指针调用的,访问权限也是按照基类的。很简单的东西,要解释清楚却很费事 :)
回复 点赞
lugas 2014年01月10日
这个问题不错,该解释的都解释了,mark一下。
回复 点赞
发动态
发帖子
C++ 语言
创建于2007-09-28

3.1w+

社区成员

24.8w+

社区内容

C++ 语言相关问题讨论,技术干货分享
社区公告
暂无公告