C++中多态实现的关键——虚函数
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++中多态实现的关键——虚函数的更多相关文章
- C++中为什么构造函数不能是虚函数,析构函数是虚函数
一, 什么是虚函数? 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离:用形象的语 ...
- C++基础 (7) 第七天 多态的原理 纯虚函数和抽象类 依赖倒置原则
1 昨日回顾 2 多态的原理 1 要有继承 2 要有子类重写父类的虚函数 3 父类指针(或者引用)指向子类对象 (动态联编 虚函数表 3 证明vptr指针的存在 4 vptr指针在构造父类的时候是分步 ...
- C++中的抽象类及纯虚函数的实现与否
1.含有纯虚函数的叫抽象类 2.抽象类(一般是基类)中的纯虚函数无论函数体实现与否,都没有关系,系统会自动忽略 3.继承自抽象类的子类,必须要实现父类的纯虚函数才可以实例化对象 4.抽象类不允许实例化 ...
- c++ 多态问题(在虚函数里调用虚函数)
最近在看cocos2d-x的源码,非常感激cocos2d作者的开源精神.在看代码的过程中感觉两个方向让我受益,1.把之前从书中看到的c++知识,明白了怎么运用.2.学习作者驾驭代码的巧妙方法. 看co ...
- C++中的多态与虚函数的内部实现
1.什么是多态 多态性可以简单概括为“一个接口,多种行为”. 也就是说,向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法).也就是说,每个对象可 ...
- 详解C++中的多态和虚函数
一.将子类赋值给父类 在C++中经常会出现数据类型的转换,比如 int-float等,这种转换的前提是编译器知道如何对数据进行取舍.类其实也是一种数据类型,也可以发生数据转换,但是这种转换只有在 子类 ...
- C++Review1_多态和虚函数
继承是实现多态的基础.虚函数是实现多态的方法.虚函数.多态.继承都是紧密相关的概念.而继承是所有概念的基础: 多态:简单来讲就是接口一样,实现多样.多态是指通过基类的指针或者引用,在运行时动态调用实际 ...
- 【转载】 C++多继承中重写不同基类中相同原型的虚函数
本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...
- 你好,C++(37)上车的人请买票!6.3.3 用虚函数实现多态
6.3.3 用虚函数实现多态 在理解了面向对象的继承机制之后,我们知道了在大多数情况下派生类是基类的“一种”,就像“学生”是“人”类中的一种一样.既然“学生”是“人”的一种,那么在使用“人”这个概念 ...
随机推荐
- luogu2173 [ZJOI2012]网络
题目链接 problem 给出一个无向图,每条边有一种颜色.每种颜色都构成一个森林.需要完成以下操作. 修改点权 修改边的颜色 询问某种颜色的森林中某条路径上点权最大值 solution 颜色数量不超 ...
- 【python基础语法】函数的作用域和内置函数和关键字(第7天课堂笔记)
一.函数的作用域: 1.全局变量 2.局部变量 3.global 二.内置函数 1.常见的内置函数 print : 输出 input : 输入 type : 查看数据类型 id : 获取数据的内存地址 ...
- P4735 最大异或和 /【模板】可持久化Trie
//tire的可持久化 //线段树的可持久化——主席树 //可持久化的前提:本身的拓扑结构在操作时不变 //可以存下来数据结构的所有历史版本 //核心思想:只记录每一个版本与前一个版本不一样的地方 / ...
- python进阶----深拷贝&浅拷贝
复制需要区分,,复制的是源文件的数据,还是指向源文件数据的地址 1.引用 b=a时,理解为b指向了a指向的数据,相当于引用复制 a=[1,2] b=a #验证复制的是数据还是地址 #1.查看ab的 ...
- vue添加swiper的正确方式亲测---切图网
在vue项目中,我们在做图片轮播的方式和传统切图不同,传统切图中我们一般采用非常强大的swiper来完成,而在vue中一般依赖vue-awesome-swiper组件来完成(vue-awesome-s ...
- VMware与Centos系统安装之重置root密码
VMware与Centos系统安装之重置root密码 今日任务 1.Linux发行版的选择 2.vmware创建一个虚拟机(centos) 3.安装配置centos7 4.xshell配置连接虚拟 ...
- Linux下搭建asp.net运行环境
最近有个项目,是在Windows平台下开发的,需要把 asp.net web应用移植到 CentOS下,甚是头疼: 翻阅资料,发现Jexus是个可行的方案,下面是官方对Jexus的定义: 什么是Jex ...
- 安装Jenkins到Ubuntu(APT)
运行环境 系统版本:Ubuntu 16.04.4 LTS 软件版本:Jenkins-2.176.2 硬件要求:最低内存:256MB.磁盘:1GB 安装过程 1.配置APT-Jenkins存储库 APT ...
- wxpython 简单例子:显示文本框的窗口显示鼠标位置
简单例子来自教程: #!/bin/env python import wx class MyFrame(wx.Frame): def __init__(self): wx.Frame.__init__ ...
- 怎么解决Chrome浏览器“Failed to load resource: net::ERR_INSECURE_RESPONSE”错误?
用科学方法安装的arcgisServer,需要修改系统时间,但是修改了系统时间,可能会出各种问题, office 不能正确验证,chrome 不能正常使用,访问网页, 如果直接输入本地地址进行访问的话 ...