【C++】多态 - 虚函数/虚析构函数以及虚函数表

什么是多态:

指不同对象收到相同消息时或相同对象收到不同消息时产生不同的动作。

这里先说下为什么会用到虚函数:

以下面的程序为例:

【C++】多态 - 虚函数/虚析构函数以及虚函数表_第1张图片

 

这个程序中,Carp是Fish的继承类,而Carp中覆盖了Swim这个方法,在MakeFishSwim这个函数中,要使用Fish类的形参,而你将yourFish这个Carp类的实参传递给了这个函数,让他执行Swim这个函数,这会发生什么,上面的程序运行结果:

这说明了什么?说明在MakeFishSwim这个程序中,它定义它的形参是Fish类型的,虽然你将yourFish这个Carp类传到了它那里,它仍然认为yourFish是Fish类的,并调用了Fish类Swim。

显然我们的初衷并不是这样,是希望对应的类执行自己的方法,那怎么避免这种情况呢?这就需要虚函数了。

虚函数的定义很简单,直接在父类方法定义最前面加上关键字“virtual”即可!在父类这个函数前一定得加virtual,子类的话,可以不加,系统编译时候会帮忙加,不过加上是好习惯。

举例:

【C++】多态 - 虚函数/虚析构函数以及虚函数表_第2张图片

虚析构函数:

当我以父类指针指向一个子类时候,比如我这样写:  Fish  *fish1  = new Carp;这样写是可行的!如果我没有把Fish类的析构函数用virtual修饰,那么在main中调用析构函数时,也就是我写  delete fish,只会调用父类的析构函数,而不会调用子类/Carp的析构函数!

当然如果一开始就创建的是子类的指针,最后销毁这个指针时,即使没有virtual修饰,也会把父类子类的析构函数都调用!

综上,虚函数的另一大重要作用在于,在使用父类指针指向子类的情况中,对于父类析构函数,如果没有virtual修饰,delete将不会作用到子类中的析构函数,会造成资源未释放,内存泄漏等隐患。

virtual 限制:

1. virtual不能修饰全局函数,必须是某个类的函数成员

2. virtual 不能修饰静态成员函数

3. virtual不能修饰内联函数

4. virtual不能修饰构造函数

注意:如果一个类,本意就不会被继承,那么请不要用vitual修饰它的成员函数,因为这样会造成内存的浪费:任何带有虚函数的类,会自动创建一个虚函数表指针,在32位系统中,占4个字节,这可是实打实的内存啊,不需要的话,千万别定义虚函数。

实现原理:

在父类中 ,只要我们有虚函数成员,系统就会给他创建一个成员:虚函数表指针,注意,是个指针,指向虚函数表,虚函数表中存放的都是,这个父类创建的虚函数的入口地址,这个地址指向相应的虚函数。

对于它的子类来说,如果它没有创建自己的虚函数,它继承了父类以后,会创建自己的虚函数指针,注意,这里的虚函数指针值与父类是不同的,也就是说它的虚函数表首地址不同,而虚函数表里指向的虚函数入口地址与父类的虚函数入口地址一样!因为它没有创建自己的虚函数!

如果它创建了自己的虚函数,那么它的虚函数表里对于的虚函数首地址就不同了,就指向了它自己创建的虚函数!

【C++】多态 - 虚函数/虚析构函数以及虚函数表_第3张图片

【C++】多态 - 虚函数/虚析构函数以及虚函数表_第4张图片

创建了自己的虚函数后:

【C++】多态 - 虚函数/虚析构函数以及虚函数表_第5张图片

你可能感兴趣的:(C++)