散分,虚函数的一个典型例子

来源:百度文库 编辑:神马文学网 时间:2024/04/29 01:42:33
主  题:散分,虚函数的一个典型例子
作  者:zhr_23 (zhr_23)
等  级:
信 誉 值:100
所属论坛:C/C++ C++ 语言
问题点数:20
回复次数:9
发表时间:2005-8-8 16:42:53
#include
class A
{
public:
A();
~A();
virtual void foo() { cout << "A::Vfoo() is called" << endl;}
void function() {...}
};
class B: public A
{
public:
B();
~B();
virtual void foo() { cout << "B::Vfoo() is called" << endl;}
void function() { ...};
void main()
{
A * a = new B;
a->foo(); //B的被调用
a->function();//A的被调用
}
// a->foo(); 在这里,a虽然是指向A的指针,但是被调用的虚函数(foo)却是B的,为什么?这个是虚函数的什么特性?
回复人:dlyy(魑魅魍魉) () 信誉:1002005-8-8 16:51:06得分:3
这个应该是多态的特性吧~
通过A的指针,构造出一个B的对象,调用B的方法。
“虚函数是为了实现多态, 也就是要用基类指针调用派生类的方法”
这句话在我的本本上记了很久……
Top
回复人:tab0tab(t) () 信誉:1002005-8-8 16:57:35得分:2
这是用基类指针指向子类的实体,运行时当然要运行子类代码了
Top
回复人:lyclowlevel() () 信誉:1002005-8-8 17:18:55得分:4
首先,virtual 是有传递性的。在你的代码中的体现就是:在B的定义中去除foo这个函数前面的那个virtual的话,该函数还是被认为是虚拟函数的;
其次,每个类如果具有虚拟函数(这些虚拟函数有的是自己定义的,有的是通过继承得到的),那么,编译器在存储该类的定义时,会用一个指针(名叫vptr)指向一个数组X。该数组X中的元素的类型是函数指针类型。每一个元素指向一个虚拟函数。这个数组X的学名叫虚拟函数表。这张虚拟函数表的构建方法是:这张虚拟函数表包含基类的虚拟函数,也包含派生类的虚拟函数表。但是,如果派生类中有重写了基类的虚拟函数的话,那么虚拟函数表中对应的元素指向的是派生类的,而不是指向基类的。对于你的代码而言,本来X中存放的函数指针指向了A中的foo,但是因为B重写了这个虚拟函数,于是,编译器将这个指针重新定向,让它指向B中的foo;
然后,如果在程序中出现一个类对象(假设为a),a调用了它的一个成员函数,而该函数是虚拟函数。那么,编译器就会先判断a的实际类型,从而获得正确的vptr,然后在它的虚拟函数表中寻找到相对应的函数指针,最后通过这个函数指针调用正确的虚拟函数。对于你的代码,a的实际类型是B,所以a的虚拟函数表中的函数指针指向的函数是B中的foo;
还有,每个类只有一张虚拟函数表,所有的对象共用这张表。
Top
回复人:junguo(junguo) () 信誉:1052005-8-8 17:19:03得分:3
这就是虚函数的多态特性了,也是虚函数最重要的性质!
通过多态,可以通过基类的指针来调用子类的函数,这样编程过程中,所有子类有相同的操作的时候,就可以直接通过基类去调用虚函数,而不需要一个类型一个类型的去写操作。
虚函数的原理是在它的对象存储空间有一个虚函数表!
http://blog.csdn.net/junguo/archive/2005/04/30/369279.aspx
Top
回复人:dongpy(51-->ARM) () 信誉:1162005-8-8 17:56:19得分:2
定义了虚函数的类,其对象有VPTR指针,指向一张虚函数指针表。
虚函数的调用,是通过指针VPTR和偏移量,从虚函数指针表中找到对应虚函数地址,然后执行该函数。
A * a = new B;
a指向的对象,其VPTR指向的是类B的虚表。
Top
回复人:smjacky(jacky) () 信誉:1002005-8-8 21:12:00得分:0
这是C++的精髓,好好理解理解吧
Top
回复人:xzgyb(老达摩) () 信誉:1102005-8-9 9:11:06得分:2
编译器对于
a->foo();的调用形式如下
int * vptr = ( int * ) * ( int * )a;
int foo_offset = 0;
int * foo_addr = ( int * ) * ( vptr + foo_offset );
typedef void ( * PFunc )();
PFunc pFunc = ( PFunc ) foo_addr;
pFunc();
Top
回复人:zousoft(菜菜鸟的战斗诗歌) () 信誉:1002005-8-9 9:31:46得分:4
我是这样理解的:
A * a = new B; // 一个基类类型的指针a,指到了子类对象B的头上。
a->function(); // 这个是为什么要引入虚函数和多态的原因,虽然表面上看起来像是调用B的function(),但由于a是A类的指针。所以无论它指到谁的头上,调用的仍然是A类的函数!假如换成“.”操作,比如:b=new B;b.function()的话,就可以调用类B的了。
a->foo(); // 这个就是虚函数和多态的作用了,解决了上面的问题,指到谁就掉谁。这样可以做到动态选择对哪个对象操作。注意:多态操作是通过对基类指针操作实现的。
Top
回复人:Darkay_Lee() () 信誉:1002005-8-9 9:40:50得分:0
地球人都知道了:)
Top
该问题已经结贴 ,得分记录: dlyy (3)、 tab0tab (2)、 lyclowlevel (4)、 junguo (3)、 dongpy (2)、 xzgyb (2)、 zousoft (4)、
_xyz