引言:在我们去购买汽车票的时候,我们总会遇到成人全价,学生打折的情况。不同的对象(成人、学生)进行同一操作(购买车票),得到不同的结果(全价、打折),此时这就是我们多态思想的体现。那么我们如何使用C++实现多态呢?请听我接下来的讲解。
更多有关C++的知识详解可前往个人主页:计信猫
一,虚函数
1,虚函数的定义
虚函数就是一个被virtual修饰的成员函数,如下所示:
class person
{virtual void buy(){cout << "全价" << endl;}
};
2,虚函数的重写
虚函数的重写(覆盖):派生类中有一个与基类的虚函数完全相同的虚函数。此时就可以说是基类的虚函数被子类重写(覆盖)了。
完全相同:
1,函数的返回值相同
2,函数的名字相同
3,函数的参数相同(只看参数类型)
如下的例子所示:
class person
{virtual void buy(){cout << "全价" << endl;}
};
class student :public person
{virtual void buy(){cout << "打折" << endl;}
};
此时派生类的buy函数就重写了基类的buy函数。
3,虚函数重写的两个例外
(1)协变
协变的定义是基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用。协变的出现导致了虚函数重写的返回值不同,但是并不会出现报错。如下便是一个协变的试例:
class A
{};
class B :public A
{};
class person
{virtual A* buy(){cout << "全价" << endl;}
};
class student :public person
{virtual B* buy(){cout << "打折" << endl;}
};
(2)析构函数的重写
在我们编写程序时,更加建议将析构函数写成虚函数的形式,以便应对以下情况:
int main()
{A* a = new B;delete a;return 0;
}
所以我们可以将A与B的析构函数进行如下处理:
class A
{
public:virtual ~A(){}
};
class B :public A
{
public:virtual ~B(){}
};
此时B类的析构函数仍然重写了A的析构函数,虽然在表面上它们的函数名并不相同,但是在底层处理的时候,其实它们的析构函数名称都被编译器处理为了destructor,因此其实它们的函数名是相同的。
4,override和final
(1)override
override关键字用于检查派生类的某个虚函数是否重写了基类的虚函数,如果没有重写,那么在编译阶段就会发生报错。如下所示:
class person
{/*virtual void buy(){cout << "全价" << endl;}*/
};
class student :public person
{virtual void buy()override{cout << "打折" << endl;}
};
此时派生类的buy函数并没有发生重写,那么我们的override关键字就会让程序在编译阶段出现报错:
(2)final
final关键字修饰的虚函数则不能进行重写。如下方式使用:
class person
{virtual void buy()final{cout << "全价" << endl;}
};
那么此时基类person的buy函数就不能被它的派生类重写,不然就会发生报错。
二,多态
所以有了前边我们所学习的虚函数知识的支持,那么我们就可以实现一个简单的多态了。此时以前边的成人和学生买票为例(成人买票就是全价,学生买票就是打折)。
在实现多态之前,我们需要遵循一下规则:
1,需使用基类的指针或引用调用虚函数
2,被调用的函数为virtual修饰的(即为虚函数)
那么我们实现的多态如下:
class person
{
public:virtual void buy(){cout << "成人全价" << endl;}
};
class student :public person
{
public:virtual void buy(){cout << "学生打折" << endl;}
};
void func(person& obj)
{obj.buy();
}
int main()
{person p;student s;func(p);func(s);return 0;
}
此时我们代码一走,那么结果如下:
三,纯虚函数
纯虚函数的定义十分简单,只需要在虚函数的声明之后加上=0即可,如下:
virtual void buy()=0
纯虚函数一般不会进行实现,有声明即可。
四,抽象类
含有纯虚函数的类即为抽象类,如下的person类就为抽象类。
class person
{
public:virtual void buy()=0
};
如果派生类不重写纯虚函数,那么其派生类也为抽象类。