虚函数&多态

时间:2021-03-28 21:53:31

1.虚函数--类的成员函数前面加上virtual关键字,则这成员函数称为虚函数。

虚函数重写--当在子类中定义一个与父类完全相同的虚函数时,则称子类这个函数重写(也称覆盖)了父类的这个虚函数。

#include<iostream>
using namespace std;
class Person
{
public:
virtual void BuyTickets() //父类的virtual不能省略
{
cout<<"买票"<<endl;
}
};
class Student : public Person
{
public:
virtual void BuyTickets() //虚函数重写
{
cout<<"买票半价"<<endl;
}
};
int main()
{
Person p;
Student s;
Person *ptr; //父类的指针

ptr = &p; //父类对象赋给父类指针
p.BuyTickets();

ptr = &s; //子类对象赋给父类指针
s.BuyTickets();
return 0;
}
 首先,我们先看是否 虚函数重写;在此处是虚函数重写。

其次,看是否是父类的指针或者引用;在此处是父类的指针。

所以,满足以上两点,构成多态,故在调用时按对象进行调用。

运行结果:

虚函数&多态

总结:

(1)子类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)

(2)父类中定义了虚函数,在子类中该函数始终保持虚函数的特性。

(3)只有类的成员函数才能定义为虚函数。

(4)静态成员函数不能定义为虚函数。

(5)如果在类外定义虚函数,只能在声明函数时加上virtual 关键字,类外定义不能加上virtual。

(6)构造函数不能为虚函数,可以将operator=定义为虚函数,但最好不要,因为使用时容易引起混淆。

(7)不要在构造函数和析构函数里调用虚函数,在构造函数和析构函数对象是不完整的,可能会发生未定义的行为。

(8)最好把父类的析构函数声明为虚函数。

(这是为什么呢?析构函数比较特殊,因为子类析构函数和父类的析构函数的名称不一样,但是在这里构成覆盖,这里因为编译器做了特殊处理。把父类析构函数定义为虚函数,如果构成多态,则会按对象去调用,就不会造成内存泄露)。

2.纯虚函数--在成员函数的形参后面加上=0,则成员函数为纯虚函数。包含纯虚函数的类叫抽象类。纯虚函数不能实例化出对象。一般期望子类重写的函数定义为纯虚函数。

class Person
{
virtual void Display() = 0; //纯虚函数
protected:
string _name; //姓名
};
class Student : public Person
{};
3.友元与继承

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

4.继承与静态成员

基类里面定义了static成员,则整个集成体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static实例。