C++基础多态

目录

学习内容:

1. 多态

1.1 多态的实现

1.2 函数重写(override)

1.3 虚函数

1.4 使用多态实现的实例 

1.5 虚函数的底层实现 

1.6 重载(voerload)、重写(override)和隐藏(hide)的区别 (面试)

1.7 纯虚函数(抽象类)

1.8 虚析构函数

课外作业:

自己封装 栈和队列

队列


学习内容:

1. 多态

        面向对象的三大特征:封装、继承、多态

        多态:就是多种状态,能够实现“一物多用”,是实现泛型编程的重要途径

1.1 多态的实现

        父类的指针或引用可以指向子类的对象,进而调用子类中重写的父类的虚函数

1.2 函数重写(override)

        1> 函数重写是发生在父子类中

        2> 要求在子类中定义与父类中函数原型相同的函数

                原型相同:返回值类型、函数名、参数列表都相同

1.3 虚函数

        1> 定义格式:在定义函数前加关键字 virtual,此时的函数就是虚函数

        2> 需要在父类中定义虚函数,子类中可以进行重写也可以不重写

        3> 当一个类中,如果定义了虚函数,那么该类会增加一个指针的大小,这个指针指向虚函数表

        4> 如果一个类中的某个函数定义成虚函数,那么该类的子子孙孙类中的该函数都是虚函数,即使没有加virtual

#include <iostream>using namespace std;class Animal
{
public:string name;      //名称
public:Animal() {}Animal(string n):name(n) {}~Animal() {}//定义虚函数virtual void voice(){cout<<"~~~~~~~~"<<endl;}
};//定义羊类
class Sheep:public Animal
{
public:int leg;       //腿的个数
public:Sheep(){}Sheep(string n, int l):Animal(n), leg(l){}~Sheep(){}//重写父类的函数void voice() override{cout<<"咩咩咩~~~~~"<<endl;}//定义子类自己的函数void show(){cout<<"我是:"<<name<<"   有"<<leg<<"条腿"<<endl;}};int main()
{Sheep s1("喜羊羊", 2);s1.voice();            //调用的是自己的s1.Animal::voice();      //调用父类的s1.show();//定义一个父类的引用,目标为子类Animal &r1 = s1;r1.voice();               //调用父类的//r1.show();return 0;
}

1.4 使用多态实现的实例 

//在父类中定义虚函数virtual void jungle(){boss_blood -= attack;     //每攻击一次野怪就掉血}
};int Hero::boss_blood = 1000;      //初始血量//定义具体英雄类
class Assassin:public Hero
{
public:int speed ;      //移速加成
public:Assassin(){}Assassin(string n, int a, int s):Hero(n, a+50), speed(s){}~Assassin(){}//重写子父类的虚函数void jungle(){boss_blood -= attack;     //每攻击一次野怪就掉血}};//定义具体英雄类
class Master:public Hero
{
public:int speed ;      //移速加成
public:Master(){}Master(string n, int a, int s):Hero(n, a+5), speed(s){}~Master(){}//重写父类的虚函数void jungle(){boss_blood -= attack;     //每攻击一次野怪就掉血}
};//功能函数完成打野功能
void fun(Hero &hero)
{hero.jungle();cout<<hero.name<<"攻击了暴君,目前暴君血量为:"<<hero.boss_blood<<endl;
}int main()
{Assassin h1("李白", 70, 300);    //实例化刺客Master h2("妲己", 30, 250);         //实例化法师fun(h1);fun(h2);return 0;
}

1.5 虚函数的底层实现 

1.6 重载(voerload)、重写(override)和隐藏(hide)的区别 (面试)

        1> 函数重载:函数名相同,形参列表必须不同

                1、作用域相同

                2、函数名相同

                3、参数列表必须不同(个数、类型)

                4、有无 virtual 都无所谓

                5、跟返回值没有关系

        2> 函数重写:子类中重写父类的虚函数

                1、作用域发生在父子类中

                2、函数原型相同(返回值、参数个数、参数类型、函数名)

                3、父类中的函数必须要有 virtual 关键字

        3> 函数隐藏:子类中定义与父类同名的函数

                1、作用域发生在父子俩中

                2、函数名相同

                3、返回值可以不同

                4、参数相同

                5、没有virtual修饰

1.7 纯虚函数(抽象类)

        1> 对于有些类而言,类中的相关成员函数没有实现的意义,主要是让子类来完成重写操作的

        2> 以便于使用父类的指针或引用指向子类对象,调用子类中重写的父类的虚函数

        3> 我们就可以将这样的函数设置成纯虚函数

        4> 定义格式: virtual 返回值类型 函数名(形参列表) = 0;

        5> 要求子类中必须对这些纯虚函数进行重写

        6> 抽象类:包含纯虚函数的类叫做抽象类,抽象类是不能实例化对象的

        7> 如果包含纯虚函数的子类中没有重写其虚函数,那么其子类也是抽象类,子类中的该函数也还是纯虚函数

#include <iostream>using namespace std;class shape
{
public:double perimeter;double area;public:
virtual void output() = 0;};class Circle:public shape
{
private:double radius;
public:Circle():radius(0){}Circle(double r):radius(r){}~Circle(){}void output(){cout<<"周长="<<2*radius<<"pi"<<endl;cout<<"面积="<<radius*radius<<"pi"<<endl;}
};class Rectangle:public shape
{
private:double width;double height;
public:Rectangle():width(0),height(0){}Rectangle(double w,double h):width(w),height(h){}~Rectangle(){}void output(){cout<<"周长="<<2*(width+height)<<endl;cout<<"面积="<<width*height<<endl;}
};int main()
{//shape s;                //抽象类不能实例化对象Circle c1(2.5);Rectangle r1(3.5,4.2);//定义父类指针shape *ptr = &c1;       //定义父类指针指向子类对象ptr->output();           //父类?子类?cout<<"************************"<<endl;//ptr->shape::output();return 0;
}

1.8 虚析构函数

        1> 当使用父类指针指向子类对象时,构造时会正常先构造父类后构造子类,但是在使用delete释放内存空间时,由于父类指针的作用域,只作用在子类的父类空间内,所以,只会调用父类的析构函数,子类自己的空间就泄露了

        2> 此时可以使用虚析构函数来解决:定义析构函数时,在函数头前面加关键字virtual即可

        3> 虚析构函数能正确引导delete关键字,在释放父类空间时,把子类的空间一并释放

        4> 如果父类的析构函数为虚析构函数,那么该类的子子孙孙类中的析构函数都是虚析构函数

 

#include <iostream>using namespace std;class shape
{
public:double perimeter;double area;public:
shape(){cout<<"shape ::构造函数"<<endl;}
virtual ~shape(){cout<<"shape ::析构函数"<<endl;}         //定义虚析构函数
virtual void output() = 0;};class Circle:public shape
{
private:double radius;
public:Circle():radius(0){}Circle(double r):shape(),radius(r){}~Circle(){}void output(){cout<<"周长="<<2*radius<<"pi"<<endl;cout<<"面积="<<radius*radius<<"pi"<<endl;}
};class Rectangle:public shape
{
private:double width;double height;
public:Rectangle():width(0),height(0){}Rectangle(double w,double h):shape(),width(w),height(h){cout<<"rectangle::构造函数"<<endl;}~Rectangle(){cout<<"rectangle::析构函数"<<endl;}void output(){cout<<"周长="<<2*(width+height)<<endl;cout<<"面积="<<width*height<<endl;}
};int main()
{shape *ptr = new Rectangle(3,5);         //在堆区申请一个子类的对象,用父类的指针指向ptr->output();         //正常输出delete ptr;return 0;
}

课外作业:

自己封装 栈和队列

#include <iostream>
#include <string.h>using namespace std;
using namespace std;class Stack
{
private:int* elements; // 用于存储栈中的元素int capacity;  // 栈的最大容量int top;       // 栈顶指针,指向最后一个元素的位置public:// 构造函数Stack(int size):capacity(size),top(-1) {elements = new int[capacity]; // 分配内存给动态数组}// 析构函数~Stack(){delete [] elements;}// 赋值运算符重载Stack & operator=(const Stack &other){if(this != &other){int * temp = new int[other.capacity];for(int i = 0; i <= other.top; ++i)temp[i] = other.elements[i];delete [] elements;elements = temp;capacity = other.capacity;top = other.top;}return *this;}// 获取栈顶元素的引用int & Top(){return elements[top];}// 判断栈是否为空bool empty() const{return top == -1;}// 返回栈中当前元素的数量int getsize() const{return top + 1;}// 扩容void expend(){capacity *= 2; // 容量翻倍int * newdata = new int[capacity];for(int i = 0; i <= top; i++) // 复制旧数组到新数组{newdata[i] = elements[i];}delete [] elements; // 释放旧数组内存elements = newdata; // 指向新数组}// 入栈操作void push(int e){if(top >= capacity - 1) // 如果栈已满,则扩容{expend();}elements[++top] = e; // 将元素添加到栈顶}// 出栈操作int pop(){if(empty()) // 如果栈为空,则输出错误信息{cout << "Stack is empty" << endl;}return elements[top--]; // 返回并移除栈顶元素}
};int main()
{Stack s1(3);s1.push(2);s1.push(5);s1.push(8);s1.push(5);s1.push(3);s1.push(1);s1.push(9);s1.pop();cout<<"top element:"<<s1.Top()<<endl;cout<<"stack size:"<<s1.getsize()<<endl;Stack s2 = s1;cout<<"s2.top element:"<<s2.Top()<<endl;cout<<"s2.stack size:"<<s2.getsize()<<endl;return 0;
}

队列

 

#include <iostream>using namespace std;class queue
{
private:int * elements; // 用于存储栈中的元素int capacity;    // 栈的最大容量int front;    //队头int rear;     //队尾
public://构造函数queue(int size):capacity(size),front(0),rear(0) {elements = new int[capacity];}//析构函数~ queue(){delete [] elements;}//拷贝赋值queue & operator=(const queue &other);//访问第一个元素int Front();//访问最后一个元素int Back();//判空bool empty();//判断大小int getsize();//向队列尾部插入元素void push(int e);//删除首个元素void pop();//二倍扩容void expend(){capacity *= 2; // 容量翻倍int * newdata = new int[capacity];for(int i = front; i <= rear; i++) // 复制旧数组到新数组{newdata[i-front] = elements[i];}delete [] elements; // 释放旧数组内存front=0;rear = rear - front;// 重置front和rear,以适应新数组elements = newdata; // 指向新数组}};queue &queue::operator=(const queue &other)
{if(this != &other){capacity = other.capacity;front = other.front;rear = other.rear;elements = new  int[capacity];for(int i=front;i<rear;i++){elements[i-front] = other.elements[i];}}return *this;
}int queue::Front()
{return elements[front];
}int queue::Back()
{return elements[rear-1];
}bool queue::empty()
{return rear == front;
}int queue::getsize()
{return rear-front;
}void queue::push(int e)
{if(rear>=capacity)   // 如果队列已满,则扩容{expend();}elements[rear] = e;  //队尾插入元素rear++;
}void queue::pop()
{if(empty()){cout<<"queue is empty"<<endl;}else{front = (front+1) %capacity;}
}int main()
{queue q1(3);q1.push(2);q1.push(1);q1.push(3);q1.push(7);q1.push(5);q1.push(9);q1.push(4);//q1.pop();queue q2=q1;q1.pop();q1.pop();cout<<"队列大小为:"<<q1.getsize()<<endl;cout<<"队头元素为:"<<q1.Front()<<endl;cout<<"队尾元素为:"<<q1.Back()<<endl;cout<<"q2队列大小为:"<<q2.getsize()<<endl;cout<<"q2队头元素为:"<<q2.Front()<<endl;cout<<"q2队尾元素为:"<<q2.Back()<<endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415585.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DeepWalk【图神经网络论文精读】笔记

链接: DeepWalk【图神经网络论文精读】_哔哩哔哩_bilibili [内容总结::] - deep walk 解决图嵌入问题&#xff1a;将结点压缩成低维向量随机游走&#xff08;类似NLP生成句子&#xff09; 优点与缺点: 相关学习资料 - word2vec 开山必读论文 - DeepWalk 论文阅读 - 代…

若楠带你初识OpenCV(1)-- 视频、图片基础处理,颜色获取

文章目录 OpenCV一、核心功能二、初识OpenCV1. 安装OpenCV2. 读取图片3. 读取灰度图4. 图片保存5. 视频文件读取6. 区域截取7. 提取RGB通道颜色8. 合并颜色通道 总结 OpenCV OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学…

MES 系统中工艺管理--工艺指令管理

一.生产系统柔性&#xff0c;高复用性需求。 工艺路线---------生产线 工序------工位 工艺指令-----具体工步 二.工艺指令分类 1、工艺要求支持配置指令、站点后在过点时&#xff0c;自动调用指令执行。物料、工步、人员作为预留设置&#xff1b; 2、指令主要分ABCD四类&…

Git基础教程:掌握版本控制的秘密

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 &#x1f680; 什么是Git &#x1f680; 在本系列博客中所实现的目标 一&#xff1a; &#x1f525; Git 初识 二&#xff1a; &#x1f525; Git 安装 &#x1f34a; Linux-c…

GAMES202——作业4 Kulla-Conty BRDF(BRDF的预计算、重要性采样)

目录 任务 实现 预计算E() 预计算Eavg Bonus1&#xff1a;重要性采样 在实时渲染中使用预计算数据 结果 任务 完成 Kulla-Conty BRDF 模型&#xff0c;关键在于计算 BRDF 的补偿项 f ms &#xff0c;而 f ms 的计算需要 E ( ) 和 E avg 两个前置变量。 1.预计算E() …

【pgAdmin4】创建/删除:数据库Database和数据库表Table

目录 0.环境 1.简介 2.详细步骤 1&#xff09;创建数据库 法一&#xff1a;UI界面创建 法二&#xff1a;sql语句创建数据库 2&#xff09;创建数据库表 查看数据库表 查看数据库表内容 法一&#xff1a;UI界面创建数据库表 法二&#xff1a;sql语句创建数据库表 3&…

快专利与慢专利:速度与质量的天平

在当今快速发展的科技时代&#xff0c;专利成为了创新成果的重要保护手段。然而&#xff0c;不同的创新有着不同的节奏&#xff0c;由此也产生了“快专利”与“慢专利”之分。快专利以其迅速的申请和应用&#xff0c;为创新者抢占市场先机&#xff1b;慢专利则凭借深度的研发和…

【Redis之一:下载安装Redis】

Redis下载与安装 一、下载 Redis 安装包1、 Windows 安装包下载 二、安装Redis1、 Windows 安装Redis 三、配置 Redis1、 Windows 中配置 Redis&#xff08;1&#xff09;配置访问密码&#xff08;2&#xff09;重启 Redis 服务 三、访问 Redis1、命令行访问 Redis&#xff08;…

【福利】最新可用!谷歌搜索和谷歌学术的镜像网站

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 内容来自&#xff1a;https://www.80srz.com/posts/1633.html 谷歌搜索镜像 Google搜索镜像1&#xff1a;https://g.savalone.com/ Google搜索镜像2&…

Python基础笔记

一、python基础1.1 基础知识1.1.1 注释 注释&#xff1a;在程序中对程序代码进行解释说明的文字。 作用&#xff1a;注释不是程序&#xff0c;不能被执行&#xff0c;只是对程序代码进行解释说明&#xff0c;让别人可以看懂程序代码的作用&#xff0c;能够大大增强程序的可读性…

LabVIEW电机多次调用

在LabVIEW中&#xff0c;为实现对多个电机的独立控制&#xff0c;工程师可以采用可重入VI、动态VI调用、多任务结构或面向对象编程等方法。每种方法都有其优点和适用场景&#xff0c;选择合适的方法能有效提升系统的性能和可维护性。 在LabVIEW中&#xff0c;如果需要多次调用…

遥控器显示分别对应的无人机状态详解!!

1. 电量显示 遥控器电量&#xff1a;遥控器上通常会显示自身的电池电量&#xff0c;以提醒用户及时充电。 无人机电量&#xff1a;部分高端遥控器还会显示无人机的电池电量&#xff0c;以进度条或百分比的形式表示&#xff0c;帮助用户了解无人机的续航能力。 2. 飞行模式与…

Mybatis框架——缓存(一级缓存,二级缓存)

本章将简单介绍Mybatis框架中的缓存&#xff0c;欢迎大家点赞➕收藏&#xff0c;蟹蟹&#xff01;&#xff01;&#xff01;&#x1f495; &#x1f308;个人主页&#xff1a;404_NOT_FOUND &#x1f308;MyBatis环境搭建步骤&#xff08;超全解析&#xff01;&#xff01;&am…

hackme靶机攻略

1.通过nmap扫描靶场ip 2.目录扫描 3.找出文件存储位置&#xff0c;看看哪里可以上传文件 4.注册账号登录一下 点击search 5.输入1 and 11 -- 1 and 12 --看看有无SQL注入 6.判断字段数 1 order by 3 -- 说明字段数是3 7.查看数据库 -1 union select database(),2,3 # 8.查…

【Linux】使用Linux实现小程序 - 进度条

目录 一、缓冲区二、回车换行的概念三、进度条的设计3.1 版本1&#xff08;没有配合场景&#xff09;3.2 版本2&#xff08;配合场景&#xff09;3.3 版本3&#xff08;美化进度条&#xff09; 结尾 一、缓冲区 C/C语言&#xff0c;会针对标准输出&#xff0c;给我们提供默认的…

Python数据分析实战,兰州市二手房市场深度分析

作为购房者&#xff0c;除了关注地段与价格外&#xff0c;房屋的总价与面积的关系&#xff0c;以及房屋朝向的选择&#xff0c;同样是决策过程中的关键因素。那么&#xff0c;兰州市的二手房市场中&#xff0c;房屋总价与面积之间究竟存在怎样的关系&#xff1f;各个朝向的房源…

day-48 分割回文串

思路 利用dfs算法&#xff0c;用ids表示当前所指向字符的位置&#xff0c;依次判断s.charAt(ids),s.charAt(ids)s.charAt(ids1)…是否为回文字符串&#xff0c;如果是则加入链表p,再递归调用dfs函数 解题过程 每次调用dfs函数后记得还原现场 Code class Solution {public St…

宝藏!《联盟自控基础班筑基题库》(凤凰篇) 1-8章:甄选部分

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;初试《自控基础班筑基题库》(凤凰篇)。 Part1&#xff1a;资料封面&目录 Part2&#xff1a;资料各个章节具体内容 第1章 自动控制的基本概念 第2章 控制系统的数学模型 第3章 控制系统的时域分析 第4章 根轨迹法…

探索ArrayList的线程不安全性

文章目录 概要示例代码原因解决用 synchronized 保证安全添加元素其他方法 总结 概要 要测试ArrayList的线程不安全性&#xff0c;可以创建多个线程同时对 ArrayList 进行修改操作&#xff08;如添加、删除元素&#xff09;&#xff0c;并观察是否会引发异常或数据不一致的问题…

unity游戏开发——标记物体 一目了然

Unity游戏开发:标记物体,让开发变得一目了然 “好读书&#xff0c;不求甚解&#xff1b;每有会意&#xff0c;便欣然忘食。” 本文目录&#xff1a; Unity游戏开发 Unity游戏开发:标记物体,让开发变得一目了然前言1. 什么是Tag&#xff1f;2. Unity中如何添加和管理Tag步骤1&am…