c++中的virtual虚函数的使用

来源:互联网 发布:星际淘宝王 编辑:程序博客网 时间:2024/06/18 10:57

c++类中,对于基类和派生类中函数名字相同的成员函数方法

对于重载:处于同一作用域,参数类型不同,函数名相同

对于隐藏(只能出现在继承结构中):函数名相同的都是隐藏,调用的时候必须加基类的作用域

对于覆盖:virtual虚函数(返回值,名字,参数类型都相同)

这里我们就不重点区分这些不同的方法

***************这里我们重点介绍一下虚函数***********************

virtual虚函数

我们首先来构造一个类(举例说明)

#include <iostream>#include <typeinfo>using namespace std;class Base{public:Base(int a):ma(a){cout<<"Base()"<<endl;}~Base(){cout<<"~Base()"<<endl;}virtual void show(){cout<<"Base::show()"<<endl;}virtual void show(int){cout<<"Base::show(int)"<<endl;}private:int ma;};class Derive:public Base{public:Derive(int data):mb(data),ma(data),Base(data){cout<<"Derive()"<<endl;}~Derive(){cout<<"~Derive()"<<endl;}void show(){cout<<"Derive::show()"<<endl;}void show(int){cout<<"Derive::show(int)"<<endl;}private:int ma;int mb;};int main(){Derive d(20);Base *pb = &d;pb->show();cout<<typeid(pb).name()<<endl;cout<<typeid(*pb).name()<<endl;cout<<sizeof(Derive)<<endl;return 0;}


我们根据结果来分析一下


在 main函数中,我们构造了一个派生类的对象d,所以他会首先调用基类的构造(构造ma),然后调用了派生类的构造函数

然后我们又写了一个基类的指针去指向派生类对象,那么为什么他会调用派生类的show函数呢?????????????

原因是这样的:

当派生中有与基类虚函数的函数名相同,参数列表,返回值相同的成员函数会被自动也处理成虚函数

所以呢,现在派生类的两个show函数都是虚函数

我们定义了一个基类的指针,它调用show函数首先是要在基类里面找有没有这个show()函数,如果此时基类的show()是一个普通的函数,

他自然回去调用基类的show()函数,如果基类的show函数是一个虚函数,此时就是动态绑定(多态),有虚函数存在,它就会在虚函数

表里面找,

这个虚函数表会在编译阶段生成如下图




我们在man函数中生成了一个派生类对象,每一个对象都会拥有同一张虚函数表,在对象创建的时候,

都会有一个指向这张表的指针vfptr(存放表地址),pb->show()这一句会把基类函数在虚函数表里覆盖掉,如图。。。

在运行阶段:::::::::::::

动态绑定::::::::::::::

汇编大概是这样的:

mov ecx dword ptr[pb]   (找前四个字节:也就是vfptr)

mov eax dword ptr[ecx]  把vfptr 放在寄存器里

call eax  找虚函数的地址(vfptr指向虚函数的地址)

所以当运行的时候它会去找派生对象的vfptr->派生类对象的虚函数表,找到那个show函数:打印出来,结构体

的大小也就变成了16,这也就解释为什么pb的类型是base*,而*pb是Derive类型的

——————————————————————————————————————————————

都到这里,那怎么才能作为虚函数呢

其实呢,要写成虚函数必须要有两个条件:

1:必须要有对象的存在

2:函数地址可循

**********************************************

那哪些函数可以写成虚函数呢?????????

1》:inline函数可不可以呢?????

答案是否定的,为什么呢,那是因为它不满足第二个条件,内联函数在调用的时候只是在函数调用点将其代码展开

不会产生函数符号(函数名:代表函数入口地址),所以函数不可寻址,所以不能作为虚函数

2》模板函数?????????

答案是否定的,因为在编译时期虚函数表(vfptable)就要产生,而模板函数在使用(运行)的时候才会被实例化

编译时期就不知道虚函数的大小了(要存函数地址),所以也不符合第二个条件

3》构造函数???????

答案是否定的,原因很简单,在构造函数结束的时候对象才能生成,所以构造函数不能作为虚函数(对象还没生成)

所以不符合第一个条件

4》虚构函数???????

答案是肯定的,析构函数符合以上两个要求:有对象,由函数名(当然,析构函数写成虚函数其实可以解决大问题的,以后再说)

原创粉丝点击