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

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》虚构函数???????

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

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值