C++之多态(上篇)

1.多态是什么

1.多态的概念:通俗来讲,就是多种形态。具体来讲,就是在做同一种事情的时候,不同的对象去做会产生不同的状态。
2.举个例子:就如同旅游去景点买票,如果是成人,那就要全票购买,如果是儿童或者学生,那就有优惠。

2.多态的定义

1.多态的构成条件:
多态是在不同继承关系的类对象,去调用同一函数,产生不同的行为。
那么,构成如此情况需要两个条件:
①:必须通过基类指针或者引用调用该函数。
②:必须调用的是虚函数,且派生类必须对基类的该函数进行重写。
如下图:
在这里插入图片描述
使用不同的对象去调用,得到了不同的结果。
2.虚函数:
如上图,被virtual修饰的函数,就是虚函数,同样也是构成多态的不可缺少的功臣,有了它的修饰,才能构成多态。
3.虚函数的重写:
①:虚函数的重写(覆盖,在多态的原理下面会将覆盖),意思是在派生类中要有一个和基类一模一样的虚函数(返回值,参数,函数名都一样),称派生类重写了基类的虚函数。
②:还有一点要注意的是,在派生类重写基类虚函数时,虚函数前可加可不加virtual,不管加不加,此时这个函数都是虚函数。

3.多态的原理

1.虚函数表
①:大家一定很疑惑,多态到底是怎么实现的,为什么虚函数的重写就可以成为构成多态,其实在内部,给虚函数制定了一个特殊的位置,那就是虚函数表。如图:
在这里插入图片描述
从图中我们可以看到,在类对象p中除了我们所定义的私有成员外,发现一个__vfptr的成员,其实这就是虚函数表,里面只放了虚函数表的地址,为什么这样说呢,如下图:
在这里插入图片描述
通过查看类对象的所占用的字节大小,可以发现,在32位操作系统下,私有成员占有8个字节,那么多出的4个字节应该就是__vfptr所占有的大小。
②:经过修改代码,如下:

class Person
{
public:
	virtual void func()
	{
		cout << "Person::func()" << endl;
	}
	virtual void func1()
	{
		cout << "Person::func1()" << endl;
	}
	void func2()
	{
		cout << "Person::func2()" << endl;
	}
private:
	char a = 'A';
	int b = 1;
};
class Student : public Person
{
public:
	virtual void func()
	{
		cout << "Student::func()" << endl;
	}
private:
	int c = 2;
};
int main()
{
	Person p;
	Student s;
}

运行后,结果如图:
在这里插入图片描述
由图可以看见:
1.派生类有两部分成员,一部分是继承下来的,虚拟表就在这部分中,另一部分就是自己的成员。
2.派生类和基类的虚拟表有不一样的地方,首先,地址不一样,其次,func函数发生了重写,所以s中的存在的就是重写后的,虚函数重写就是覆盖,覆盖是指虚拟表中虚拟函数的覆盖,重写是语法的叫法,覆盖是原理层的叫法。
3.只有虚函数才能放进需表里,func2就没放入虚表里面。
4.虚函数表的本质就是一个存放虚函数的数组,最后一个虚函数后存的是nullptr。
5.派生类虚函数表生成顺序:
首先,将基类的虚函数表拷贝到自己的虚函数表中;其次,将派生类重写的基类的函数覆盖基类的该函数;最后,将自己新加的虚函数按照声明顺序排在已有的虚函数表后面。
2. 多态的原理
1.如下代码:

class Person
{
public:
	virtual void BuyTicket() 
	{ 
		cout << "买票-全价" << endl; 
	}
};
class Student : public Person 
{
public:
	virtual void BuyTicket()
	{ 
		cout << "买票-半价" << endl;
	}
};
void Func(Person& p)
{
	p.BuyTicket();
}
int main()
{
	Person Mike;
	Func(Mike);
	Student Johnson;
	Func(Johnson);
	return 0;
}

如图,运行可以得下图:
在这里插入图片描述
如图,蓝线和红线分别代表不同的路线,分别在基类和派生类的虚函数表中找到所对应的虚函数,这样就产生了不同对象调用相同函数产生了不同的形态。
2.出现这样的情况,是因为满足多态以后的函数调用,不是在编译时确定的,而是在运行时到对象去找的。而不满足多态的函数调用,是在编译时就已经确定好的。
3.静态绑定与动态绑定
①:静态绑定:是在程序编译的时候就已经确定了程序的行为,所以也叫前期绑定,也称静态多态。(重载就是一种静态绑定)
②:动态绑定:是在程序运行期间,根据拿到的具体类型确定程序的行为,所以也叫后期绑定,也称动态多态。(就如重写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值