目录
- 一、概念及定义
- 二、虚函数重写的特例
- 三、final和override
- 四、抽象类
一、概念及定义
概念:在继承关系下的不同类,调用同一个函数,产生不同的行为,叫作多态。
图示:
定义:必须通过基类的指针或者引用调用虚函数;被调用的函数必须是虚函数。类里的函数的返回类型前加上virtual就是虚函数,子类继承父类的虚函数叫作重写,重写的是虚函数的实现,该虚函数的返回类型、函数名、参数列表都要与父类相同(有两个特例,后面再谈)。
class Person
{
public:virtual void func(){cout << "全价" << endl;}
};class Student :public Person
{
public:virtual void func(){cout << "半价" << endl;}
};void test1(Person* ps)//通过基类的指针
{ps->func();//调用虚函数
}void test2(Person& ps)//通过基类的引用
{ps.func();//调用虚函数
}int main()
{Person p;Student s;test1(&p);test1(&s);test2(p);test2(s);return 0;
}
注:子类的虚函数加不加virtual都没关系,但是父类一定要有virtual,否则就不是虚函数了。一般为了规范,子类也最好加上virtual
二、虚函数重写的特例
1️⃣协变
父子类的虚函数返回类型可以不相同。基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用。
class A {};
class B : public A {};
class Person {
public:virtual A* f() { return new A; }
};
class Student : public Person {
public:virtual B* f() { return new B; }
};
2️⃣析构函数的重写
如果基类的析构函数是虚函数,只要派生类的析构函数定义了,不管加不加virtual,都是虚函数。两个析构函数的函数名不相同也构成重写,因为编译器有作特殊处理,编译后析构函数的名称统一处理成destructor。
class Person
{
public:virtual ~Person(){cout << "~Person()" << endl;}
};class Student :public Person
{
public:virtual ~Student(){cout << "~Student()" << endl;}
};int main()
{Person* p = new Person;Person* s = new Student;delete p;delete s;return 0;
}
三、final和override
1️⃣final关键字修饰虚函数,该虚函数不能被重写
2️⃣override关键字是用来检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
四、抽象类
概念:包含纯虚函数的类叫抽象类。纯虚函数:在虚函数的后面写上 =0,就称为纯虚函数。抽象类不能实例化对象,继承它的派生类只有重写纯虚函数才能实例化出对象。
class Animal
{
public:virtual void Action() = 0;//抽象类,纯虚函数声明即可
};class Dog :public Animal
{
public:virtual void Action()//对纯虚函数进行重写{cout << "running!" << endl;}
};class Bird :public Animal
{
public:virtual void Action()//对纯虚函数进行重写{cout << "flying!" << endl;}
};int main()
{Animal* d = new Dog;Animal* b = new Bird;d->Action();b->Action();return 0;
}