1.多态的作用

在面向对象程序设计中,使用多态能够增强代码的可扩充性,,即程序需要增加或修改部分功能时,只需修改少量代码就能够达到目的,此外多态也能起到精简代码的作用。

而实现多态的关键点,就是虚函数如何使用。

虚函数

1.虚函数的使用方法

.基同类与派生类同时拥有的同名同参数表的函数,在设计时,最好将其声明为虚函数,只需在函数前面加上关键字virtual即可

下面通过一个具体的例子来说明

#include<iostream>
using namespace std;
class Shape{
public:
void Printf(){
cout<<" The Shape has been called"<<endl;
}
};
class Rectangle:public Shape{
public:
void Printf(){
cout<<"The Rectangle has been called"<<endl;
} };
class Circle:public Shape{
public:
void Printf(){
cout<<"he Circle has been called"<<endl; }
};
void Print(Shape &a)
{ a.Printf();
}
void Print(Rectangle &a)
{ a.Printf();
}
void Print(Circle &a)
{ a.Printf();
}
int main()
{
Shape a;
Rectangle b;
Circle c;
Print(a);
Print(b);
Print(c);
return 0;
}

以上程序定义了一个基类Shape 派生出了Rectangle 和 Circle

又定义了三个全局函数用来输出Shape 和Rectangle ,Circle

程序运行结果如下

可以看出三个Print()除了参数,其他完全一样,因此需要一种方法,将Printf()的参数表变得足够灵活,能够同时识别Shape Rectngle Circle

这个时候就可以用到虚函数

具体如下

#include<iostream>
using namespace std;
class Shape{
public:
virtual void Printf(){
cout<<" The Shape has been called"<<endl;
}
};
class Rectangle:public Shape{
public:
void Printf(){
cout<<"The Rectangle has been called"<<endl;
} };
class Circle:public Shape{
public:
void Printf(){
cout<<"he Circle has been called"<<endl; }
};
void Print(Shape &a)
{ a.Printf();
} int main()
{
Shape a;
Rectangle b;
Circle c;
Print(a);
Print(b);
Print(c);
return 0;
}

可以看出,将三个Prinft()函数简化为了一个,而且参数类型为基类的引用

而且在调用时将三种不同的参数类型传入Printf()也不会报错,程序运行结果也是对的

这说明Printf()声明为虚函数后,能够被基类对象正确识别。

并且使用虚函数可以大大简化代码量

2虚函数的识别原理

实际上,对于任何一个含有虚函数,或者其基类含有虚函数的类来说,在其对象的存储空间的最前端,都有一个虚函数表,该虚函数表中存储着该对象的虚函数的地址

多态的函数调用语句被被编译成个根据基类指针或引用所指向的对象中存放的虚函数表的地址,在虚函数表中查询虚函数地址,并调用虚函数的一系列指令

3.虚析构函数

先运行如下程序

#include<iostream>
using namespace std;
class A
{
public:
~A(){
cout<<"A destructor"<<endl;
}; };
class B:public A{ public:
~B(){
cout<<"B destructor"<<endl;
};
};
int main()
{
A *p=new B;
delete p;
return 0;
}

程序的运行结果说明 最后一句delete p,并没有释放掉B的内存,而只释放掉了A的内存,只引发了A的析构函数被调用,被没有调用B的析构函数

这是因为这条语句是静态联编的,编译器进行到delete p 这一句时,并不知道p此时到底指向的是哪个对象,所以只能根据p的类型是A *来调用A的析构函数,

我们希望delete p这样的语句能够足够智能的根据p所指向的对象来执行相应的析构函数

那么将析构函数声明为虚析构函数是一种有效的解决方式

#include<iostream>
using namespace std;
class A
{
public:
virtual ~A(){
cout<<"A destructor"<<endl;
}; };
class B:public A{ public:
~B(){
cout<<"B destructor"<<endl;
};
};
int main()
{
A *p=new B;
delete p;
return 0;
}

将基类析构函数声明为虚函数后

程序运行结果如下



类B的析构函数被正确调用,说明开辟的类B的空间被释放掉

C++中多态实现的关键——虚函数的更多相关文章

  1. C++中为什么构造函数不能是虚函数,析构函数是虚函数

    一, 什么是虚函数? 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离:用形象的语 ...

  2. C++基础 (7) 第七天 多态的原理 纯虚函数和抽象类 依赖倒置原则

    1 昨日回顾 2 多态的原理 1 要有继承 2 要有子类重写父类的虚函数 3 父类指针(或者引用)指向子类对象 (动态联编 虚函数表 3 证明vptr指针的存在 4 vptr指针在构造父类的时候是分步 ...

  3. C++中的抽象类及纯虚函数的实现与否

    1.含有纯虚函数的叫抽象类 2.抽象类(一般是基类)中的纯虚函数无论函数体实现与否,都没有关系,系统会自动忽略 3.继承自抽象类的子类,必须要实现父类的纯虚函数才可以实例化对象 4.抽象类不允许实例化 ...

  4. c++ 多态问题(在虚函数里调用虚函数)

    最近在看cocos2d-x的源码,非常感激cocos2d作者的开源精神.在看代码的过程中感觉两个方向让我受益,1.把之前从书中看到的c++知识,明白了怎么运用.2.学习作者驾驭代码的巧妙方法. 看co ...

  5. C++中的多态与虚函数的内部实现

    1.什么是多态         多态性可以简单概括为“一个接口,多种行为”.         也就是说,向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法).也就是说,每个对象可 ...

  6. 详解C++中的多态和虚函数

    一.将子类赋值给父类 在C++中经常会出现数据类型的转换,比如 int-float等,这种转换的前提是编译器知道如何对数据进行取舍.类其实也是一种数据类型,也可以发生数据转换,但是这种转换只有在 子类 ...

  7. C++Review1_多态和虚函数

    继承是实现多态的基础.虚函数是实现多态的方法.虚函数.多态.继承都是紧密相关的概念.而继承是所有概念的基础: 多态:简单来讲就是接口一样,实现多样.多态是指通过基类的指针或者引用,在运行时动态调用实际 ...

  8. 【转载】 C++多继承中重写不同基类中相同原型的虚函数

    本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...

  9. 你好,C++(37)上车的人请买票!6.3.3 用虚函数实现多态

    6.3.3  用虚函数实现多态 在理解了面向对象的继承机制之后,我们知道了在大多数情况下派生类是基类的“一种”,就像“学生”是“人”类中的一种一样.既然“学生”是“人”的一种,那么在使用“人”这个概念 ...

随机推荐

  1. 从零开始一个个人博客 by asp.net core and angular(三)

    这是第三篇了,第一篇只是介绍,第二篇介绍了api项目的运行和启动,如果api项目没什么问题了,调试都正常了,那基本上就没什么事了,由于这一篇是讲前端项目的,所以需要运行angular项目了,由于前端项 ...

  2. 《手把手教你构建自己的 Linux 系统》学习笔记(4)

    汇编链接器(Binutils) 这是一个软件包,这个软件包其实是一个工具集,里面含有了大量的用于汇编程序活着读取二进制文件相关的程序. CC 它是一条命令的别名,这条命令的作用是使用 GCC 的 C ...

  3. springboot打成war包并携带第三方jar包

    1.修改打包方式为war     <packaging>war</packaging> 2.添加第三方依赖的jar到pom     我的第三方jar包在resoueces目录下 ...

  4. Linux centos7 安装 phpMyAdmin

    yum install httpd php mariadb-server –y搭建lamp运行环境之后安装phpMyAdmin遇到的一些问题记录一下 1.官网下载phpMyAdmin压缩包 wget ...

  5. P1308 统计单词数(cin,getline() ,transform() )

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  6. 「JOI 2017 Final」绳

    题意 loj 做法 首先我们观察到最后能折起来的充要条件是: 只有两个颜色,除首尾外,所有颜色块内的数量为偶数 因为为偶数,我们进一步推论: 所有颜色块起始位置奇偶性相同 然后因为增与减都会有相同花费 ...

  7. private、public、this关键字

    private关键字 概念:私有的,一种权限修饰符,用来修饰类的成员 特点:被修饰的成员只能在本类中访问 用法: - 1. private 数据类型 变量名: - 2. private 返回值类型 方 ...

  8. 吴裕雄--天生自然 JAVA开发学习:Java 开发环境配置

  9. atcoder Keyence Programming Contest 2020 题解

    比赛地址 A 题意:给一个\(n*m\)的初始为白色的矩阵,一次操作可以将一行或一列染成 黑色,问至少染出\(k\)个黑点的最少操作次数. \(n\),\(m\)<=100,\(k\)<= ...

  10. WebApp开发-Zepto

    zepto.js自己去官网下载哈. DOM操作 $(document).ready(function(){ var $cr = $("<div class='cr'>插入的div ...