🏠专栏介绍:浅尝C++专栏是用于记录C++语法基础、STL及内存剖析等。
🎯每日格言:每日努力一点点,技术变化看得见。
文章目录
多态的概念
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
在生活中,我们在乘坐公交车时,不同的人会有不同的折扣力度,例如:学生卡8折,老人卡免费等等。对于同一件事,会发生不同的不同形态就称为多态。
多态的定义及实现
多态的构成条件
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。
例如:下图中Student类继承了Person类。两个对象在调用同一个函数takeBus时,一个执行的是Person中的getTickets,一个执行的是Student中的getTicket。这就是调用同一个函数takeBus,却产生了不同的行为。
继承中要构成多态还有两个条件:
- 必须通过基类的指针或者引用调用虚函数
- 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
在讲述这两个条件之前,我们先来聊聊什么是虚函数↓↓↓
虚函数
虚函数:即被virtual修饰的类成员函数称为虚函数。
下面代码中,getTicket成员函数被virtual修饰,因而它是虚函数。↓↓↓
class Person
{
public:
virtual void getTicket()
{
cout << "全票" << endl;
}
};
虚函数的重写
那虚函数有什么用途呢?如果将基类的成员函数用virtual修饰成为虚函数后,派生类中可以对该成员函数进行重写(覆盖)。
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
下面代码中的Person类与Student类中的getTicket构成了虚函数重载↓↓↓
#include <iostream>
using namespace std;
class Person
{
public:
virtual void getTicket()
{
cout << "全票" << endl;
}
};
class Student : public Person
{
public:
//派生类中可以省略virtual关键字,但不推荐
//void getTicket() --> 这样写也可以
virtual void getTicket()
{
cout << "8折" << endl;
}
};
void takeBus(Person* p)
{
p->getTicket();
}
void takeBusByReference(Person& p)
{
p.getTicket();
}
int main()
{
Student s;
Person p;
s.getTicket();
s.Person::getTicket();
cout << "================" << endl;
takeBus(&s);
takeBus(&p);
cout << "================" << endl;
takeBusByReference(s);
takeBusByReference(p);
return 0;
}
从上面代码中可以看出,如果从s.getTicket();
及s.Person::getTicket();
两行代码来看,重写(覆盖)与隐藏并没有多大区别。没有显示指定调用基类的同名函数时,会默认调用派生类的;如果显示指定了基类作用域,则会调用基类的。
重写(覆盖)与隐藏的区别在于,重写执行takeBus及takeBusByReference时,对于Person对象和Student对象,它会调用对应对象的同名(同名、同参数列表、同返回值)函数。如果是隐藏,则都只会执行指针或引用类型对应类的函数,而不会执行它的子类的同名函数(同名、同参数列表、同返回值)。
虚函数重写(覆盖)的两个特例:
协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同,但两个不同的返回值之间必须构成子类与父类关系。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。
下面代码给出了协变示例↓↓↓
#include <iostream>
using namespace std;
class Base
{
};
class Son : public Base
{
};
class Person
{
public:
virtual Base* ptest()
{
cout << "Person's ptest()" << endl;
return &b;
}
virtual Base& refertest()
{
cout << "Person's refertest()" << endl;
return b;
}
private:
static Base b;
};
Base Person::b = Base();
class Student : public Person
{
public:
virtual Son* ptest()
{
cout << "Son's ptest()" << endl;
return &s;
}
virtual Son& refertest()
{
cout << "Son's refertest()" << endl;
return s;
}
private:
static Son s;
};
Son Student::s = Son();
void test