多态
面向对象的三大特性:
封装使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用,而多态目的是为了接口重用。也就是说无论传递过来的是哪个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。1
虚函数
虚函数基本介绍
在C++中,多态性是通过虚函数来实现的。虚函数在函数前使用virtual关键词声明。
这样当一个类的成员函数说明为虚函数后,就可以在该类的(直接或间接)派生类中定义与其基类虚函数原型相同的函数。这时,当用基类指针或引用指向这些派生类对象时,可以为该对象调用虚函数并执行该函数的派生类版本。
在派生类中声明重写函数时可使用 virtual 关键字,但它不是必需的;虚函数的重写始终是虚拟的。
一个简单的例子:
#include <iostream>
using namespace std;
class N{
public:
virtual void display(){cout << "N" << endl;}
};
class A:public N{
public:
virtual void display(){cout << "A" << endl;} //virtual关键词非必须
};
int main(){
A* aa = new A();
static_cast<N*>(aa)->display(); //"A"
return 0;
}
虚函数与普通同名函数区别
那么非虚函数在派生类中有同名的函数(参数相同或参数不同)会出现什么情况呢?这个在上一篇文章的情况二中有所提及(C++虚函数分析[1]–同名函数继承二义性问题)。这里再总结一下:
#include <iostream>
using namespace std;
class Base {
public:
virtual void vir_display(){cout << "Base::vir_display" << endl;}
void display(){cout << "Base::display" << endl;}
};
class Derived : public Base {
public:
void vir_display(){cout << "Derived::vir_display" << endl;}
void display(){cout << "Derived::display" << endl;}
};
int main() {
Derived* d=new Derived();
Derived *pDerived = d;
Base *pBase = d;
pBase->vir_display(); //"Derived::vir_display"
pDerived->vir_display(); //"Derived::vir_display"
pBase->display(); //"Base::display"
pDerived->display(); //"Derived::display"
}
结合上面代码,输出用注释给出,可以得到结论:
当使用指针或引用调用类的函数时,以下规则将适用:
1. 根据为其调用的对象的基本类型来解析对虚函数的调用。
2. 根据指针或引用的类型来解析对非虚函数的调用。2
纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类中都要自己定义实现方法。含有纯虚函数的类称为抽象类,不能生成对象。
如果在派生类中没有实现纯虚函数,那么派生类也将成为抽象类,不能够生成对象。
声明方法:
virtual void funtion()=0;
虚函数表
虚函数表是虚函数实现的机制,于是想要理解虚函数需要去理解虚函数表
这里别人的博客写的非常清晰,图文并茂,就直接给出链接了:
陈皓专栏–C++ 虚函数表解析
相关概念
静态绑定、动态绑定