1007多态02多态的原理剖析

52 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

1 原理解释

类中只有一个非静态的成员的函数 它并不属于类的对象上面。所以它类似一个空类,空类的大小是一个字节。

当父类中有virtual函数,就相当于父类里面含有四个大小的指针,这个指针名字叫做:vfptr(虚函数表指针): v - virtual/f - function/ptr - pointer

这个指针会指向虚函数表:vftable

v - virtual/f - function/table - table

内部会记录虚函数表的地址 &Fat::spr(要加上作用域)

子类: 如果没有发生重写的情况,那就是一个继承了,就是把父类所有的内容全部拿到子类,父类的指针也要拿过来一份:vfptr,并且指向子类的虚函数表vftable:记录的也是虚函数&Fat::spr(要加上作用域)

当你发生重写之后,那么子类会把子类中虚函数表中的内容做一个覆盖操作,即:子类中的虚函数表内部会替换成子类的虚函数地址。 &Son::spr(要加上作用域)

父类没有发生改变,父类中的指针没有发生改变,在父类依然是有的,子类只是替换子类的虚函数表。

当父类的指针或者引用指向子类对象时候,会发生多态。

2 原理举例

#include<iostream>
using namespace std;
class Fath
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	 void spr()
	{
		cout << "父类" << endl;
	}
};

class Son1 :public Fath
{
public:
	void spr()
	{
		cout << "子类1" << endl;
	}
};

class Son2 :public Fath
{
public:

	void spr()
	{
		cout << "子类2" << endl;
	}

};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

void DoSpr(Fath & fath)
{
	fath.spr();
}
//
//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

void test()
{
	cout << "sizeof Fath = " << sizeof(Fath) << endl;
}


int main() {

	test();

	system("pause");

	return 0;
}

1660642557175.png

输出:

sizeof Fath = 1 请按任意键继续. . .

class Fath
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	 virtual void spr()
	{
		cout << "父类" << endl;
	}
};

1660642437138.png

输出:

sizeof Fath = 4 请按任意键继续. . .

class Fath
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	 virtual void spr()
	{
		cout << "父类" << endl;
	}
};
class Son1 :public Fath
{
public:
	
};
void test()
{
	cout << "sizeof Son1 = " << sizeof(Son1) << endl;
}

1660642785192.png

输出:

sizeof Son1 = 4 请按任意键继续. . .

class Fath
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	 virtual void spr()
	{
		cout << "父类" << endl;
	}
};
class Son1 :public Fath
{
public:
	void spr()
	{
		cout << "子类1" << endl;
	}
	
};

1660642964298.png sizeof Son1 = 4 请按任意键继续. . .