【C++】多态(上)

1. 多态的构成条件

在继承中要构成多态还有两个条件:

  1. 必须通过基类指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

在这里插入图片描述

2. 多态调用特点

  • 普通调用:调用函数的对象类型是谁,就调这个类型的函数
  • 多态调用:调用 指针或引用 指向的对象,指向父类调用父类的函数,指向子类调用子类的函数

3. 虚函数

虚函数:即被virtual修饰的类成员函数称虚函数(virtual只能修饰成员函数)

3.1 虚函数的重写

虚函数的重写 又叫做 虚函数的覆盖
继承中虚函数的重写:子类继承的是父类虚函数的接口,子类重写的是子类虚函数的实现

  • 父子继承关系的两个虚函数,三同(函数名/参数/返回)

  • 三同(函数名/参数/返回)的例外:协变—>返回值可以不同,但是返回值必须都是父子类关系的指针或者引用

  • 派生类重写的虚函数可以不加virtual(建议都加上)

3.2 析构函数必须为虚函数的情况

为了使 父子类的 析构函数是虚函数(虚函数有三同特点),
析构函数统一会被处理成destructor

  • 即:delete p; 的本质其实是:
      p->destrutor() + operator delete ( p );

析构函数必须为虚函数的情况 即使用new的情况,如下:

class Person {
public:
	virtual A* BuyTicket() 
	{ 
		cout << "Person买票-全价" << endl;
		return nullptr;
	}

	virtual ~Person()
	{
		cout << "~Person()" << endl;
	}
};

class Student : public Person {
public:
	virtual B* BuyTicket()
	{ 
		cout << "Student买票-半价" << endl;
		return nullptr;
	}
	
	~Student()
	{
		cout << "~Student()" << endl;
	}
};




int main()
{
	Person* p = new Person;

	// 析构是虚函数,才能正确调用析构函数
	// p->destrutor() + operator delete(p)
	delete p;

	p = new Student;

	// p->destrutor() + operator delete(p)
	delete p;

	return 0;
}

在这里插入图片描述

4. 重载、覆盖(重写)、隐藏(重定义)的对比

在这里插入图片描述

5. C++11 override 和 final

final:

  • final 修饰类,类不能被继承
  • final 修饰虚函数,虚函数不能被重写(final 若修饰函数,只能修饰虚函数)
class Car
{
public:
 virtual void Drive() final {}
};

class Benz :public Car
{
public:
 virtual void Drive() {cout << "Benz-舒适" << endl;}
};

override:

  • 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
class Car{
public:
 virtual void Drive(){}
};

class Benz :public Car {
public:
 virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

6. 抽象类

6.1 概念

  • 在虚函数的后面写上 =0 ,则这个函数为纯虚函数。
  • 包含纯虚函数的类叫做抽象类(也叫接口类)
  • 抽象类不能实例化出对象。派生类继承后也不能实例化出对象
  • 只有重写纯虚函数,派生类才能实例化出对象。
  • 纯虚函数
    1、间接强制去派生类去重写
    2、抽象类-不能实例化出对象
class Car
{
public:
virtual void Drive() = 0;
};


class Benz :public Car
{
public:
 virtual void Drive()
 {
 cout << "Benz-舒适" << endl;
 }
};


class BMW :public Car
{
public:
 virtual void Drive()
 {
 cout << "BMW-操控" << endl;
 }
};


void Test()
{
Car* pBenz = new Benz;
 pBenz->Drive();   //这里没有用到多态,因为这是子类调用虚函数
 Car* pBMW = new BMW;
 pBMW->Drive();   //这里没有用到多态,因为这是子类调用虚函数
} 

6.2 接口继承和实现继承

  • 普通函数的继承是一种实现继承
  • 虚函数的继承是一种接口继承

7. 多态的原理

7.1 虚函数指针 和 虚函数表

  • 若类内有虚函数,类内就会多1个指针,该指针指向虚函数表,对象中的这个指针我们叫做虚函数表指针
  • 一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表,虚函数表其实就是一个函数指针数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值