C++--多态--虚函数重写、抽象类

35 篇文章 0 订阅
本文详细介绍了C++中的多态性概念,包括构成多态的条件、虚函数、重写(覆盖)、协变、析构函数重写以及override和final的使用。通过实例展示了如何通过基类指针调用派生类的虚函数实现多态行为,并对比了重载、重写和重定义的区别。此外,还讨论了抽象类和纯虚函数在实现多态中的作用。
摘要由CSDN通过智能技术生成

1. 多态的概念

  • 多态:多种形态;就是去完成某个行为,当不同的对象去完成时,会产生出不同的状态;

2. 多态的构成条件

  • 多态是在不同继承关系的类对象中调用同一函数,产生了不同的行为;
  • 必须通过基类的指针或者引用调用虚函数;
  • 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。

实现多态

  1. 前提:继承
  2. 虚函数
  3. 调用虚函数的类型必须时指针或引用
  4. 虚函数需要被重写
  5. 一般是通过父类的指针或引用调用

3. 虚函数

  • 虚函数:被virtual修饰的类成员函数。

4. 虚函数的重写

4.1 虚函数的重写(覆盖)

  • 派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名、参数列表完全相同)。
class Person
{
public:
	//虚函数
	virtual void buyTicket()
	{
		cout << "全价" << endl;
	}
};
class Student : public Person
{
public:
	//虚函数重写:
	//函数名,参数列表,返回值和父类虚函数完全相同
	virtual void buyTicket()
	{
		cout << "半价" << endl;
	}
private:
	char* _name = new char[100];	
};
void fun(Person& rp)
{
	rp.buyTicket();
}
void test()
{
	Person p;
	Student stu;
	fun(p);
	fun(stu);
}

4.2 协变

  • 派生类重写基类虚函数时,基类与派生类虚函数返回值类型不同,即基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。
class A{};
class B : public A {};
class Person
{
public:
	virtual A* Hongbao()
	{
		cout << "一毛钱" << endl;
		return new A;
	}
};
class Student : public Person
{
public:
	//协变:返回值可以不是同一个类型,但是必须是有继承关系的指针或者引用
	virtual B* Hongbao()
	{
		cout << "100元" << endl;
		return new B;
	}
	private:
	char* _name = new char[100];
};
//多态:看对象
void fun(Person& rp)
{
	rp.Hongbao();
}
void test()
{
	Person p;
	Student stu;
	fun(p);
	fun(stu);
}

4.3 析构函数的重写

  • 如果基类的析构函数为虚函数,此时派生类虚函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写。
class Person
{
public:
	//一般把析构函数定义成虚函数,产生多态行为,保证资源被正常释放
	virtual ~Person()
	{
		cout << "~Person" << endl;
	}
};
class Student : public Person
{
public:
	virtual ~Student()
	{
		if (_name)
		{
			delete[] _name;
			cout << "delete[] _name" << endl;
		}
		cout << "~Student" << endl;
	}
	private:
	char* _name = new char[100];
};
void test()
{
	Person* ps = new Student;
	delete ps;
	Person* ps2 = new Person;
	delete ps2;
}

在这里插入图片描述

4.4 override和final

  • override :检查函数是否重写了父类的某一个虚函数,强制重写;
  • final:修饰虚函数,表示该虚函数不能再被重写
class Person
{
public:
	//虚函数
	virtual void buyTicket()
	{
		cout << "全价" << endl;
	}
	//final修饰虚函数,表示该虚函数不能被子类重写
	virtual void fun()final 
	{}
};
class Student : public Person
{
public:
	//override:检查函数是否重写了父类的某一个虚函数,强制重写
	//override:体现接口(返回值、函数名、参数列表)继承,不继承实现,重写实现
	virtual void buyTicket() override
	{
		cout << "半价" << endl;
	}
	//无法重写final函数
	/*virtual void fun()
	{}*/
private:
	char* _name = new char[100];
};
//final修饰类,表示该类不能被继承
class A1 final
{};
class B1 : public A1 //不能将final类类型作为基类
{};

5. 重载、重写、重定义对比

5.1 重载

  • 两个函数在同一个作用域
  • 函数名/参数相同

5.2 重写

  • 两个函数分别在基类和派生类的作用域
  • 函数名/参数/返回值都必须相同(协变例外)
  • 两个函数必须是虚函数

5.3 重定义

  • 两个函数分别在基类和派生类的作用域
  • 函数名相同
  • 两个基类和派生类的同名函数不构成重写就是重定义

6. 抽象类

  • 纯虚函数:在虚函数后面加上 =0;
  • 抽象类:包含纯虚函数的类,也叫接口类;
  • 抽象类不能实例化出对象;
  • 派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象;
//抽象类:包含纯虚函数
//抽象类不能实例化
class A
{
public:
	virtual void fun() = 0; //纯虚函数:函数接口=0,无函数体
};
class B :public A
{
public:
	virtual void fun()
	{
		cout << "B::fun()" << endl;
	}
};
class C :public A
{
public:
	virtual void fun()
	{
		cout << "C::fun()" << endl;
	}
};
class D:public A
{};
void test()
{
	//A a1;不能实例化
	//D a2;
	B a3;//可以实例化,重写了虚函数
	C a4;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值