C++——多态

1.什么是多态?

多态简单的讲就是“一个接口,多种方法”,程序在运行时才决定调用的函数,他是面向对象的核心概念。当多态应用形参的数据交,可以接受更多的类型,当多态用于返回值类型的时候,可以返回更多类型的数据,多态可以让你的代码拥有更好的扩展性

构成多态的条件

  • 继承的存在
  • 子类要重写父类的虚函数
  • 父类的指针/引用调用重写虚函数

什么是重写:

  • 不在同一作用域内(分别在父类和子类中)
  • 基类函数必须是虚函数(virtual关键字)
  • 函数名相同,参数相同,返回值相同(协变除外)
  • 访问修饰符可以不同(公有,保护…)

场景一:父类和子类都加virtual:

class person
{
public:
	virtual void buytickets()
	{
		cout << "买票" << endl;
	}
};

class student :public person
{
public:
	virtual void buytickets()
	{
		cout << "买票——半价" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父类对象
	student s;//子类对象
	Fun(p);
	Fun(s);
}

输出为: 

当使用基类的指针或引用调用重写的虚函数时,当指向父类对象调用的就是父类的虚函数,指向子类的对象就是调用子类的虚函数。

多态跟类型无关,跟对象有关

场景二:基类中函数不加virtual

构成多态时,父类的函数必须是虚函数(virtual),为什么

class person
{
public:
	void buytickets()
	{
		cout << "买票" << endl;
	}
};

class student :public person
{
public:
	virtual void buytickets()
	{
		cout << "买票——半价" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父类对象
	student s;//子类对象
	Fun(p);
	Fun(s);
}
  • 输出为:

  • 如果将父类的virtual,那么就不能构成多态,即使你创建了子类对象和父类对象,调用的也都是父类的函数//输出“买票”。与对象无关,不能构成多态
  • 而如果将子类中的virtual去掉,而父类中的还在,同样可以构成多态。 

场景三:派生类中函数不加virtual

class person
{
public:
	virtual void buytickets()
	{
		cout << "买票" << endl;
	}
};

class student :public person
{
public:
	void buytickets()
	{
		cout << "买票——半价" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父类对象
	student s;//子类对象
	Fun(p);
	Fun(s);
}

输出为:

 

2.多态的分类:

  • 编译时的多态性(静态多态):静态多态就是重载,因为是在编译时即确定类型大小,所以称为静态多态。
  • 运行时多态性(多态多态):通过继承重写基类的虚函数实现,在程序运行时决议确定,所以称为动态

动态多态:上述代码即使动态多态

每一个带有虚函数的对象都会有一个虚函数表,虚函数表里存的时函数指针,调用的时候,指针就去虚函数表里查找。

发生重写之后,下一次父类指向我们调用的fun()函数时,它调用到的就是子类的fun()函数。

多态:

  • 多态是面向对象的三大特征直以,分为静态多态和多态多态
  • 静态多态包含函数重载与泛型编程,静态多态是程序调用函数,编译器决定使用那块可执行代码块
  • 动态多态是由继承机制及虚函数实现的,通过指向派生类的基类指针或引用,访问派生类中透明覆盖成员函数
  • 多态的作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,一适应需求的不断变化。

 

类成员函数中重载/重定义(隐藏)/重写(覆盖)的区别

1.函数重载:通常是一组功能相似但是参数类型不同的函数

  • 函数要在相同的作用域中
  • 函数名相同
  • 函数的参数列表不同(参数个数,参数顺序,参数类型),与返回值无关

 2.函数覆盖(重写):覆盖是指在派生类里覆盖基类的函数

  • 函数在不同作用域中(基类和派生类)
  • 俩个函数名相同/参数相同/返回值相同(协变除外)
  • 基类必须是虚函数(派生类最好也是)
  • 访问修饰符可以不同

3.函数隐藏(重定义):派生类的函数屏蔽了与其名字相同的基类函数

  • 函数的作用域不同(基类,派生类)
  • 函数名相同(只要名字相同就可以构成隐藏)
  • 如果派生类函数与基类函数参数相同,但是基类中没有virtual,就构成函数隐藏

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值