1 什么是多态?
多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制
程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。
多态两种条件
调用函数的对象必须是指针或者引用。
被调用的函数必须是虚函数,且完成了虚函数的重写。
原文链接:https://blog.csdn.net/weixin_42678507/article/details/89414998
#include <iostream>
class Person
{
public:
virtual void BuyTicket(int)
{
std::cout << "Adult need Full Fare!" << std::endl;
}
};
class Child : public Person
{
public:
virtual void BuyTicket(int)
{
std::cout << "Child Free!" << std::endl;
}
};
void fun(Person& obj)
{
obj.BuyTicket(1);
}
int main(void)
{
Person p;
Child c;
fun(p);
fun(c);
return 0;
}
1、调用函数就是这里的fun,参数int没有实际意义,就是为了体现函数重写必须要返回值一样、函数名一样和参数一样。
2、被调用的函数必须是虚函数,也就是说必须要在两个产生多态的函数前面加virtual关键字。
调用函数的形参对象必须是基类对象,这里是因为派生类只能给基类赋值,会发生切片操作。基类不能给派生类赋值。
3、调用函数的参数必须是指针或引用,因为派生类改变了虚表,那么这个虚表就属于派生类对象,赋值的时候只会把基类的成员给过去,虚表指针不会给。所以在调用函数的时候会发生语法检查,如果满足多态的条件,就会触发寻找虚表中虚函数地址。如果不满足条件,则会直接用基类对象调用基类函数。
上面牵扯出两个概念:
虚函数:虚函数就是在类的成员函数前面加virtual关键字。
虚函数重写:虚函数的重写:派生类中有一个跟基类的完全相同虚函数,我们就称子类的虚函数重写了基类的虚函数。
完全相同是指:函数名、参数、返回值都相同。另外虚函数的重写也叫作虚函数的覆盖
虚函数重写有一个例外错误:协变
重写的虚函数的返回值可以不同,但是必须分别是基类指针或引用和派生类指针或引用。
这种情况在VS会报错,但是在linux的G++下不会
不规范重写行为:
就是在派生类的重写函数加了virtual关键字,但是在派生类的重写函数前不加。
这样不会报错,因为继承的原因,将这个virtual的性质继承了下来,但是这样写不规范,
如果两个函数构成重写,那么要在两个函数前都加上virtual关键字。
2.抽象类
在虚函数的后面写上 =0 ,则这个函数就变成纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。
这个纯虚函数的作用就是强迫我们重写虚函数,构成多态。这样更加体现出了接口继承。
#include <iostream>
class Person
{
public:
virtual void Strength() = 0;
};
class Adult : public Person
{
public:
virtual void Strength()
{
std::cout << "Adult have big Strength!" << std::endl;
}
};
class Child : public Person
{
public:
virtual void Strength()
{
std::cout << "Child have Small Strength!" << std::endl;
}
};
————————————————
3.C++11 override 和 final
override:
override是用来检查函数是否重写,是在virtual void fun() override {}这里加上,然后来检查的。实际中,建议这样写。
final:
final是在class A final {};这里加上,目的是为了不让这个类被继承。
或者,在一个函数后加,表示这个函数不能被重写。void fun() final {}。
原文链接:https://blog.csdn.net/weixin_42678507/article/details/89414998