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