C++虚函数

目录

1.虚函数

2.C++ 多态的底层实现原理

3.纯虚函数


1.虚函数

//父类
class A {
public:
	 virtual void fun(int a) {
		cout << "A中的fun函数" << endl;
	}
};

//子类
class B : public A {
public:
	 void fun(int a) {
		cout << "B中的fun函数" << endl;
	}
};

int main()
{
	A a;
	B b;
	A* pa = &a;
	pa->fun(1);
	pa = &b;
	pa->fun(2);
	return 0; 
}

运行结果

A中的fun函数
B中的fun函数

当基类中的成员函数没有Virtual修饰时,

运行结果

A中的fun函数
A中的fun函数

结论

  • 当基类中成员函数为虚函数时,指针指向的对象,是成员函数运行的依据,与指针类型无关。
  • 当基类中成员函数不为虚函数时,指针的类型,是成员函数运行的依据,与指针指向无关。

2.C++ 多态的底层实现原理

虚表:虚函数表的缩写,类中含有virtual关键字修饰的方法时,编译器会自动生成虚表,是一个存储类成员函数指针的数据结构

虚表指针:在含有虚函数的类实例化对象时,对象地址的前四个字节存储的指向虚表的指针。

上图中展示了虚表和虚表指针在基类对象和派生类对象中的模型,下面阐述实现多态的过程:

  1. 编译器在发现基类中有虚函数时,会自动为每个含有虚函数的类生成一份虚表,该表是一个一维数组,虚表里保存了虚函数的入口地址

  2. 编译器会在每个对象的前四个字节中保存一个虚表指针,即 *vptr,指向对象所属类的虚表。在构造时,根据对象的类型去初始化虚指针vptr,从而让vptr指向正确的虚表,从而在调用虚函数时,能找到正确的函数

  3. 在派生类定义对象时,程序运行会自动调用构造函数,在构造函数中创建虚表并对虚表初始化。在构造子类对象时,会先调用父类的构造函数,此时,编译器只“看到了”父类,并为父类对象初始化虚表指针,令它指向父类的虚表;当调用子类的构造函数时,为子类对象初始化虚表指针,令它指向子类的虚表

  4. 当派生类对基类的虚函数没有重写时,派生类的虚表指针指向的是基类的虚表;当派生类对基类的虚函数重写时,派生类的虚表指针指向的是自身的虚表;当派生类中有自己的虚函数时,在自己的虚表中将此虚函数地址添加在后面。

这样指向派生类的基类指针在运行时,就可以根据派生类对虚函数重写情况动态的进行调用,从而实现多态性。

3.纯虚函数

虚函数和纯虚函数区别

  • 虚函数是为了实现动态编联产生的,目的是通过基类类型的指针指向不同对象时,自动调用相应的、和基类同名的函数(使用同一种调用形式,既能调用派生类又能调用基类的同名函数)。虚函数需要在基类中加上virtual修饰符修饰,因为virtual会被隐式继承,所以子类中相同函数都是虚函数。当一个成员函数被声明为虚函数之后,其派生类中同名函数自动成为虚函数,在派生类中重新定义此函数时要求函数名、返回值类型、参数个数和类型全部与基类函数相同。

  • 纯虚函数只是相当于一个接口名,含有纯虚函数的类称为抽象类,抽象类不能够实例化

    纯虚函数首先是虚函数,其次它没有函数体,取而代之的是用“=0”。

    既然是虚函数,它的函数指针会被存在虚函数表中,由于纯虚函数并没有具体的函数体,因此它在虚函数表中的值就为0,而具有函数体的虚函数则是函数的具体地址。

    一个类中如果有纯虚函数的话,称其为抽象类。抽象类不能用于实例化对象,否则会报错。抽象类一般用于定义一些公有的方法。子类继承抽象类也必须实现其中的纯虚函数才能实例化对象。

#include <iostream>
using namespace std;

class Base
{
public:
	virtual void fun1()
	{
		cout << "普通虚函数" << endl;
	}
	virtual void fun2() = 0;
	virtual ~Base() {}
};

class Son : public Base
{
public:
	virtual void fun2() 
	{
		cout << "子类实现的纯虚函数" << endl;
	}
};

int main()
{
	Base* b = new Son;
	b->fun1(); //普通虚函数
	b->fun2(); //子类实现的纯虚函数
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值