C++:类-多态的学习和使用
C++:类的学习和使用
- 类的多态
- 1.类的实例化
- 1.类中虚函数的使用实现多态
- C++ override使用详解
类的多态
类作用域操作符 ::
C++是面向对象的编程语言,多态的使用是父类与子类关系最直接的表现:
c++中对于多态的理解就好比如下一个例子:
①我们说一种有四条腿的动物A,并进行简单描述有四条腿的特征;
②甲猜了一种动物B,并且说了四条腿的具体特征;
③乙猜了一种动物C,并且说了四条腿的具体特征;
如上:动物A可以理解为基类,动物B.C都是子类,所以类的多态就表现在四条腿的特征(父类的(纯)虚函数)上 B和C都继承了A四条腿的特征,至于B和C因为各自物种差异而有所不同就对应了具体的子类中的(纯)虚函数定义。
https://blog.csdn.net/lling_shan/article/details/105947287
分类:
静态多态
:静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数可以调用就调,没有的话就会发出警告或者报错。
动态多态
:程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数
静态多类:
/** 程序名:book236.cpp,此程序用于演示C++类的静态多态。* 作者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <string.h>class CGirl // 定义超女类
{public:char m_name[50]; // 姓名int m_age; // 年龄int m_height; // 身高,单位:厘米cmchar m_sc[30]; // 身材,火辣;普通;飞机场。char m_yz[30]; // 颜值,漂亮;一般;歪瓜裂枣。int Show() // 显示超女基本信息的成员函数体{ printf("姓名:%s,年龄:%d,身高:%d,身材:%s,颜值:%s\n",m_name,m_age,m_height,m_sc,m_yz); }
};class CKCon:public CGirl // 定义王妃类,从超女类继承
{public:char m_ch[50]; // 称号char m_palace[50]; // 居住的宫殿int m_sal; // 奉禄int Show() // 显示王妃的称号、宫殿和奉禄{ printf("姓名:%s,称号:%s,栖:%s,奉禄:%d两银子。\n",m_name,m_ch,m_palace,m_sal); }
};int main()
{CKCon KCon;strcpy(KCon.m_name,"杨玉环"); KCon.m_age=28; KCon.m_height=168;strcpy(KCon.m_sc,"火辣"); strcpy(KCon.m_yz,"漂亮"); strcpy(KCon.m_ch,"杨贵妃");strcpy(KCon.m_palace,"华清宫"); KCon.m_sal=10000;CGirl *pGirl; // 基类的指针CKCon *pCon; // 派生类的指针pGirl=pCon=&KCon; // 都指向派生类pGirl->Show(); // 将调用的是基类的Show方法pCon->Show(); // 将调用的是派生类的Show方法
}
输出结果:
main函数中,创建的是CKCon对象,如果采用基类指针调用Show方法,变成了调用CGirl类的Show方法,而不是CKcon类的Show方法,因为pGirl是CGirl的指针,pGirl->Show方法在程序编译期间就已经设置好了。
动态多态:
动态多态是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数。
让我们对程序稍作修改,在CGirl类中,Show方法的声明前放置关键字 virtual,如下所示:
virtual int Show() // 显示超女基本信息的成员函数体
其它的代码都不变,编译并运行,结果如下:
此时,编译器看的是指针的内容,而不是它的类型。这就是多态的一般使用方式。
1.类的实例化
https://blog.csdn.net/qq_34637408/article/details/71189382
1.类中虚函数的使用实现多态
①类的多态
②1.首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。
- 如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。不要仅仅考虑到要作为基类而把类中的所有成员函数都声明为虚函数。
3、应考虑对成员函数的调用时通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问的,则应当声明为虚函数。
4.有时,在定义虚函数时,并不定义去函数体,即函数体是空的。它的作用只是定义了一个虚函数名,具体功能留给派生类去添加。
使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址。系统在进行动态关联时的时间开销时很小的,因此,多态性时高效的。
原文链接:https://blog.csdn.net/wshngyf/article/details/48092679
纯虚函数
一、定义
纯 虚函数 是一种特殊的虚函数,它的一般格式如下:
class <类名>{virtual <类型><函数名>(<参数表>)=0;…};
在许多情况下,在基类中不能对虚函数给出有意义有实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。
二、引入原因
1、为了方便使用 多态 特性,我们常常需要在基类中定义虚拟函数。
2、在很多情况下,基类本身生成对象是不合情理的。
例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为 抽象类 ,它不能生成对象。这样就很好地解决了上述两个问题。
三、相似概念
1、多态性
指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。
C++支持两种多态性:编译时多态性,运行时多态性。
a.编译时多态性:通过重载函数实现
b 运行时多态性:通过虚函数实现。
2、虚函数
虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载
3、抽象类
包含纯虚函数的类称为抽象类。
由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
注意:
(1)纯虚函数没有函数体;
(2)最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是虚函数”;
(3)这是一个声明语句,最后有分号。
纯虚函数只有函数的名字而不具备函数的功能,不能被调用。
纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对他进行定义。如果在基类中没有保留函数名字,则无法实现多态性。
如果在一个类中声明了纯虚函数,在其派生类中没有对其函数进行定义,则该虚函数在派生类中仍然为纯虚函数。
抽象类:
不用定义对象而只作为一种基本类型用作继承的类叫做抽象类(也叫接口类),凡是包含纯虚函数的类都是抽象类,抽象类的作用是作为一个类族的共同基类,为一个类族提供公共接口,抽象类不能实例化出对象。
纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。
总结:
1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)
2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
3、只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。
4、如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。
5、构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容易混淆
6、不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。
7、最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)
8、虚表是所有类对象实例共用的虚表剖析。
原文链接:https://blog.csdn.net/qq_36221862/article/details/61413619
class A{public:A();virtual ~A();void f1();virtual void f2();virtual void f3()=0;};//子类:class B : public A{public:B();virtual ~B();void f1();virtual void f2();virtual void f3();};// main 函数:int main(int argc, char* argv[]){A *m_j=new B();m_j->f1();m_j->f2();m_j->f3();delete m_j;return 0;}
f1()是一个隐藏,关于函数的隐藏,可以参考其它词条.
调用m_j->f1();会去调用A类中的f1(),它是在我们写好代码的时候就会定好的.
也就是根据它是由A类定义的,这样就调用这个类的函数.
f2()是普通的重载.
调用m_j->f2();会调用m_j中到底保存的对象中,对应的这个函数.这是由于new的B对象.
f3()与f2()一样,只是在基类中不需要写函数实现.
虚函数和抽象基类的应用:
#include <iostream>
using namespace std;//声明抽象基类Shape
class Shape
{public:virtual float area()const //虚函数{return 0.0;}virtual void shapeName()const = 0;//纯虚函数//shapeNamea函数的作用是输出具体的形状,在派生类中定义,因此声明为纯虚函数
};//声明Point类
class Point:public Shape
{public:Point(float a = 0.0, float b = 0.0){x = a;y = b;}void setPoint(float a, float b){x = a;y = b;}float getX()const{return x;}float getY()const{return y;}virtual void shapeName()const{cout<<"Point:";}friend ostream & operator <<(ostream &_cout, const Point &p){_cout<<"["<<p.x<<","<<p.y<<"]";return _cout;}protected:float x;float y;
};//声明Ciircle类
class Circle:public Point
{public:Circle(float a = 0.0, float b = 0.0, float r = 0.0):Point(a, b),radius(r){}void setRadius(float r){radius = r;}float getRadius()const{return radius;}virtual float area()const{return 3.1415926*radius*radius;}virtual void shapeName()const{cout<<"Circle:";}friend ostream & operator <<(ostream &_cout, const Circle &c){_cout<<"["<<c.x<<","<<c.y<<"],r="<<c.radius;return _cout;}protected:float radius;
};int main()
{Point point(3.2, 4.5); // 建立Point类对象pointCircle circle(2.4, 1.2, 5.6); //建立Circle类对象circlepoint.shapeName(); //静态关联cout<<point<<endl;circle.shapeName(); //静态关联cout<<circle<<endl;Shape* pt; //定义基类指针pt = &point;pt->shapeName();cout<<"x="<<point.getX()<<",y="<<point.getY()<<endl;cout<<"area="<<pt->area()<<endl;pt = &circle; //指针指向Circle类对象pt->shapeName(); //动态关联cout<<"x="<<circle.getX()<<",y="<<circle.getY()<<endl;cout<<"area="<<pt->area()<<endl;system("pause");return 0;
}
运行结果
结论:
(1)一个基类如果包含一个或一个以上纯虚函数,就是抽象基类。抽象基类不能也没必要定义对象。
(2)在类的层次结构中,顶层或最上面几层可以是抽象基类。抽象基类体现了本类族中各类的共性,把各类中共有的成员函数集中在抽象基类中声明。
(3)抽象基类是本类族的共公共接口,即就是从同一基类中派生出的多个类有同一接口。
原文链接:https://blog.csdn.net/qq_36221862/article/details/61413619
C++ override使用详解
C++ override从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法。
原文链接:https://blog.csdn.net/fanyun_01/article/details/79122136
C++:类-多态的学习和使用相关推荐
- 如何学习streamdecoder类_如何学习篇5:强化2种能力——2种学习模式之运动类:隐性学习...
[本文摘要] [注]本文所述内容为学习Yjango<学习观>相关视频之后的总结,观点归Yjango所有,本文仅作为学习之用. 阅读本节,会让你对英语这类运动类知识的学习豁然开朗,你会知道英 ...
- Java Process类的浅学习
Java Process类的浅学习 文章分类:Java编程 今天用了下java.lang.Process类,只是初步的学习,并没有深入实践,因为感觉它的用途并不是很大,偶尔才可能用上,如果要经常使用它 ...
- Java常用类(谷粒商城学习记录)
Java常用类 谷粒商城学习记录 谷粒商城学习记录 谷粒商城学习记录 干嘛老是提示我与别人的文章相似呢?真的是我自己整理的啊啊啊 老是提示与这个文章相似 https://blog.csdn.net/c ...
- Java转义工具类StringEscapeUtils的学习笔记
Java转义工具类StringEscapeUtils的学习笔记 前言 在java.commons.lang3 的包中有许多方便好用的工具类,类似于处理字符串的StringUtils,处理日期的Da ...
- java中 继承、重写、抽象类、抽象方法、多态的学习
0.复习: 0.1 静态: 1.静态成员变量:作为数据 被所有对象共享 属于类的 2.静态成员方法:工具 3.静态代码块: 初始化数据 0.2 工具类: 1.Arrays: 1.1 ...
- java 判断object类型_Java学习-方法与多态的学习心得
一 1.什么是方法重写 方法的重写或方法的覆盖(overriding) 子类根据需求对从父类继承的方法进行重新编写 重写时,可以用super.方法的方式来保留父类的方法 构造方法不能被重写 2.方法重 ...
- c++矩阵类_Python线性代数学习笔记——矩阵的基本运算和基本性质,实现矩阵的基本运算...
当学习完矩阵的定义以后,我们来学习矩阵的基本运算,与基本性质 矩阵的基本运算:矩阵的加法,每一个对应元素相加,对应结果的矩阵 例子:矩阵A和矩阵B表示的是同学上学期和下学期的课程的成绩,两个矩阵相加就 ...
- C++类的基本学习知识
面对对象:将系统看成对象的集合,对象之间通过交互作用来完成系统特定功能: 面对对象编程的特点:继承.封装.多态: 进入主题: 1.类的声明 class 类名称{ public: 公有成员(外部接口,允 ...
- java多线程多态_Java学习之多线程
多线程: (一)进程与线程 进程特点 并发与并行的区别: 多线程编程的好处: (二)多线程的建立 1,通过继承Thread类,代码如下: class MyThread extendsThread {p ...
最新文章
- 了解黑客的关键工具---揭开Shellcode的神秘面纱
- SpringInAction--Spring Web应用之SpringMvc 注解配置
- 好爽!我在上海被机器人“马杀鸡”了
- 视觉特征--ORB系列
- linux fcitx 下载网址(亲测可用)
- Seata 的AT模式需求实战_04
- lightgbm 数据不平衡_数据不平衡问题
- PyTorch 1.0 文档翻译活动期待大家的参与 | ApacheCN
- java web请求转发_Javaweb请求转发及重定向实现详解
- 使用telnet登录varnish3.x管理缓存时认证问题
- 计算机应用基础实验报告册,大学计算机应用基础实验报告册 - 2010版 - (1)
- k8s all-in-one 部署过程记录
- tracepro中文pojie版-tracepro附安装教程
- offer oracle svp_SVP - Uncyclopedia
- 基于人机环境系统工程的智慧企业建设思考
- 智能电视的“假聪明”与“真智慧”
- Intellij IDEA 设置字体的大小
- 【方差分析】之matlab求解
- 2304558-25-4,DBCO-PEG2-acid分子量是464.5的小分子PEG试剂带有PEG连接物和DBCO基团
- 腾讯投 10 亿在武汉建中部最大研发中心
热门文章
- python2中的print语句可以不用小括号。_Python 2与Python 3的区别
- python数据对比找不同,不同模式间的数据比较技术
- 【数据结构-排序】3.图解选择排序两种实现(简单选择排序/堆排序)
- 信息系统项目管理知识--项目范围管理
- UI组件之AdapterView及其子类(四)Gallery画廊控件使用
- Springboot整合shiro基于url身份认证和授权认证
- 杭电oj1003java实现
- Android开发如何双击返回键退出程序
- 类型转换:隐式转化(算数转换,整型提升,混合提升,赋值转换),强制转换【C语言】
- Hiernate 笔记