c++之虚函数

一、静态联编与动态联编

静态联编也叫做早绑定,函数名与其在内存中的可执行代码之间的对应关系在编译时就已经确定了
动态联编也叫做晚绑定,是之成员函数的调用语句在编译时不知道要执行哪个内存地址的代码。成员函数的调用会根据目标对象的动态类型在程序运行时将函数名绑定到具体的函数上

静态联编举例
class Shape
{
public:
	double calculateArea(){
		cout<<"calculateArea"<<endl;
		return 0;
	}
};
class Circle:public Shape
{
private:
	double r;
public:
	Circle(double _r):r(_r){}
	double calculateArea(){
		return 3.14*r*r ;
	}
};
class Rect:public Shape
{
private:
	double length,width;
public:
	Rect(double l,double w):length(l),width(w){}
	double calculateArea(){
		return length*width;
	}
}

int main(){
	Shape *s1=new Circle(1);
	Shape *s2=new Rect(2,1);
	s1->calculateArea();
	s2->calculateArea();
	return 0;
}

执行上面的代码后,并不会返回圆和矩形的面积,命令行内会有两行caculateArea
这里我们用基类指针Shape去指向了派生类对象,当我们调用caculateArea的时候,虽然我们实例化的对象类型是Circle和Rect,但是因为这是静态联编,Shape中的caculateArea函数在编译前就已经确定了

那么我们如果想实现用基类指针指向的派生类对象,根据不同的对象类型,调用相应的函数,就需要动态联编

虚函数的引入

虚函数就是用virtual关键字修饰的函数
virtual 函数类型 成员函数名(参数列表);

  • 虚函数在类外部定义时候可以不带virtual关键字
  • 公有继承的派生类中与基类中的虚函数原型相同但没有用virtual关键字的成员函数也是虚函数
  • 只有类的成员函数才能声明为虚函数。静态成员函数,内联函数,友元函数和构造函数都不能声明为虚函数
  • 析构函数可以是虚函数,而且通常都声明为虚函数,一旦基类的析构函数是虚函数,派生类的析构函数也是虚函数
动态联编的条件
  • 基类及其公有继承的派生类中有同名的具有public或protected访问属性的成员函数,且这两个函数的原型完全相同但是实现不同
  • 必须在基类将希望动态联编的成员函数用virtual关键字声明为虚函数
  • 必须用基类对象指针或基类对象来调用虚函数
动态联编举例
class Shape
{
public:
	virtual double calculateArea(){
		cout<<"calculateArea"<<endl;
		return 0;
	}
};
class Circle:public Shape
{
private:
	double r;
public:
	Circle(double _r):r(_r){}
	//父类中calculateArea已经是虚函数,这里可以不用加virtual,也是虚函数
	virtual double calculateArea(){
		return 3.14*r*r ;
	}
};
class Rect:public Shape
{
private:
	double length,width;
public:
	Rect(double l,double w):length(l),width(w){}
	//父类中calculateArea已经是虚函数,这里可以不用加virtual,也是虚函数
	virtual double calculateArea(){
		return length*width;
	}
};

int main(){
	Shape *s1=new Circle(1);
	Shape *s2=new Rect(2,1);
	cout<<s1->calculateArea()<<endl;
	cout<<s2->calculateArea()<<endl;
	return 0;
}

执行上面的代码后
命令行会出现
3.14
2

此时说明了s1和s2指针分别调用了其对应类型的成员函数,从而实现动态联编

虚函数的实现原理

当成员函数中有虚函数的时候,那么当我实例化对象的时候,会有一个虚函数表指针数据成员,他就指向了当前类的虚函数表
虚函数表里面存储着函数指针,根据函数指针,可以找到需要执行的代码
在这里插入图片描述

对于派生类的虚函数成员函数,也有对应的虚函数表,如果我们自己重新定义了calcArea函数,那么对应函数的指针地址将会改变
在这里插入图片描述

调用过程是,

  • 通过虚函数表指针找到虚函数表
  • 通过虚函数表找到对应函数指针
  • 通过函数指针找到需要执行的函数

纯虚函数和抽象类

动态联编要求在基类定义虚函数,有时候基类的虚函数我们不知道如何实现,对于这样一些物理上无法实现,逻辑上又不得不存在的抽象的虚函数,可以用纯虚函数来定义

纯虚函数定义格式
virtual 函数返回类型 纯虚函数名(参数表)=0

  • 虚函数表中,纯虚函数的地址为NULL
  • 包含纯虚函数的类称为抽象类,由于无法实例化一个含纯虚函数的抽象类,因此不能创建抽象类的对象,抽象类不能作为参数类型,函数返回和显示转换的类型,但是可以定义指向抽象类的指针或引用
补充:接口类

只含有纯虚函数的类叫做接口类
接口类一般表明一种能力或者协议或者规范

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值