C++之多态

本文介绍了C++中的多态概念,包括什么是多态、如何使用多态、虚函数的重写(覆盖)、多态的实现原理、抽象类的作用以及不是所有函数都能成为虚函数的原因。多态是通过虚函数和虚函数表实现,要求对象必须是引用或指针,且虚函数必须被重写。抽象类则强制派生类完成虚函数的重写,提供接口继承关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多态的知识有以下几点

 

1.什么是多态?

     简单来说就是不同的对象去完成同一个行为会产生不同的结果。

举个例子:国庆去华山游玩,一般的成人要买全价票,而我们学生买票买学生票。这就是两种不同的对象都去买票但是产生的结果却不同,一个是全价票一个是学生票。

 

2.如何使用多态?

使用多态有两个前提条件

1.调用函数的对象必须是指针或者引用

2.调用的函数必须是虚函数,而且完成了虚函数的重写

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "全价票" << endl;
	}
};
class Student : public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "学生票" << endl;
	}
};
void Fun(Person & p)
{
	p.BuyTicket();
}

那么为什么要是对象的指针或引用?

什么又是虚函数?什么又是虚函数的重写?

 

3.虚函数的重写(覆盖)

虚函数:

   所谓的虚函数就是在函数前面加上virtual这个关键字。那么他就成为了虚函数。

虚函数的重写:

   派生类中有一个跟基类的完全相同虚函数,我们就称子类的虚函数重写了基类的虚函数,完
全相同是指:函数名、参数、返回值都相同。另外虚函数的重写也叫作虚函数的覆盖。

正因为完成了虚函数的重写,才会产生不同的行为,所以这是多态的两个必要条件之一。

 

4.多态的原理

多态是如何实现的呢?

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "全价票" << endl;
	}
	int a;
};

int main()
{
	Person p;

	return 0;
}

这个类里只有一个成员变量A。我们通过调试查看监视

我们发现不仅仅是一个成员变量还有一个_vfptr。

他是一个隐藏的指针,叫虚函数表指针,他指向了虚函数表的地址,虚函数表里存放的都是虚函数的地址。

我们可以看到BuyTicket这个函数的地址就是_vfptr[0]的值。

 

再次结合一段代码来看一下关于虚函数的继承关系

class A
{
public:
	virtual void Fun1()
	{
		cout << "Fun1-A" << endl;
	}
	virtual void Fun2()
	{
		cout << "Fun2-A" << endl;
	}
        void Fun3()
	{
		cout << "Fun3-A" << endl;
	}
};
class B : public A
{
public:
	virtual void Fun1()
	{
		cout << "Fun1-B" << endl;
	}
}

A类中有两个虚函数,一个普通函数,B类继承了A类且只对Fun1完成了重写

再次观察,我们发现B类继承了A类,b也有虚函数表,因为对Fun1完成了重写,我们可以发现两个类的Fun1的地址是不相同的。

而Fun2是直接继承的,没有完成重写,所以我们可以看到他们的地址是相同的。

并且我们发现Fun3没有在虚表里出现,也就是说只有虚函数才会被放进虚函数表,普通函数不会。

 

多态就是通过传参找到对象,然后去对应对象的虚表中找到对应的虚函数调用。

所以必须传指针或者引用,不能传值,并且必须完成虚函数的重写。只有完成了重写才能实现出不同的对象完成同一行为,产生不同的结果。

 

5.抽象类:

介绍抽象类之前我们先了解一下纯虚函数

virtual void Fun1() = 0
	{
		cout << "Fun1-A" << endl;
	}

这就是纯虚函数在虚函数后面加上 =0 就是纯虚函数

抽象类就是由纯虚函数实现的。

抽象类的特点:

抽象类无法实例化出对象,派生类也无法实例化出对象,只有当派生类完成了虚函数的重写,才能实例化出对象。

这样就意味着强制我们派生类完成虚函数的重写,不然不能使用,这样的好处就是防止出现无用的虚函数。抽象类体现了接口继承关系。

 

了解完上面的知识,我们最后在了解一下有关虚函数的问题。

6.所有函数都可以是虚函数吗?

答案是NO。

1.首先内联函数无法成为虚函数,因为我们都知道虚函数的地址放在虚表里面,而内联函数没有地址,没有地址就没有办法放进虚表,所以不行。

2.静态成员函数也不行,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。

3.构造函数也不能成为虚函数,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。

 

 

 

 

 

 

 

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值