C++实用教程(四):面向对象核心多态 笔记

推荐B站视频:C++现代实用教程(四):面向对象核心多态_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV15v4y1M7fF/?spm_id_from=333.999.0.0&vd_source=a934d7fc6f47698a29dac90a922ba5a3

本项目通用的tasks.json文件和launch.json

  • tasks.json
{"version": "2.0.0","options": {"cwd": "${workspaceFolder}/build"},"tasks": [{"type": "shell","label": "cmake","command": "cmake","args": [".."]},{"label": "make","group": "build","command": "make","args": [],"problemMatcher": []},{"label": "Build","dependsOrder": "sequence","dependsOn": ["cmake","make"]},{"type": "cppbuild","label": "C/C++: g++ 生成活动文件",// "command": "/usr/bin/g++","command": "D://mingw64//bin//g++.exe","args": ["-fdiagnostics-color=always","-g","-o","${workspaceFolder}/bin/app.exe",// "-finput-charset=UTF-8",/*-fexec-charset指定输入文件的编码格式-finput-charset指定生成可执行的编码格式,*/"-finput-charset=GBK",  // 处理mingw中文编码问题"-fexec-charset=GBK"],"options": {"cwd": "${workspaceFolder}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true},"detail": "D://mingw64//bin//g++.exe"}]
}
  • launch.json
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "(gdb) 启动","type": "cppdbg","request": "launch","program": "${workspaceFolder}/bin/app.exe","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"MIMode": "gdb","setupCommands": [{"description": "为 gdb 启用整齐打印","text": "-enable-pretty-printing","ignoreFailures": true,},],"preLaunchTask": "Build","miDebuggerPath": "D://mingw64//bin//gdb.exe", // 修改为你的 gdb 路径},]
}
  • CMakeLists.txt
​cmake_minimum_required(VERSION 3.28.0)
project(project)
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_LIST)add_executable(app main.cpp ${SRC_LIST})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)​

C++的面向对象与很多其他的面向对象语言有很多不同,本质的原因是在于C++是一门极其重视性能的编程语言

>>多态是面向对象的核心

  • 这一点对于C++来说也不例外
  • 面向对象三大特性为:封装、继承、多态
    • 本人不是很喜欢C++的继承,其实是不喜欢继承
    • 封装和继承基本上是为多态而准备的
  • 面向对象是使用多态性获得对系统中每个源代码依赖项的绝对控制的能力的(大牛说的)
  • 高内聚、低耦合是程序设计的目标(无论是否面向对象,),而多态是实现高内聚,低耦合的基础

>>目录

    1.多态与静态绑定2.虚函数与动态绑定3.多态对象的应用场景与大小4.Override与Final5.Overloading与多态6.析构函数与多态7.Dynamic_cast类型转换8.typeid操作符9.纯虚函数与抽象类10.接口式抽象类

第一节:多态与静态绑定

>>多态:

  • 在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口
  • 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数

>>静态绑定:将名称绑定到一个固定的函数定义,然后在每次调用该名称时执行该定义,这个也是常态执行的方式

  • shape.h 
#ifndef SHAPE_H
#define SHAPE_H
#include <string>
#include <string_view>
#include <iostream>
class Shape{
public:Shape() = default;~Shape() = default;Shape(std::string_view name);void draw() const {std::cout<<"Shape Drawing "<<m_name<<std::endl;}
protected:std::string m_name;
};
#endif
  • shape.cpp
#include "shape.h"Shape::Shape(std::string_view name) : m_name(name){}
  • rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <string>
#include <string_view>
#include <iostream>
#include "shape.h"
class Rectangle:public Shape{
public:Rectangle() = default;~Rectangle() = default;Rectangle(double x,double y,std::string_view name);void draw() const {std::cout<<"Rectangle Drawing "<<m_name<<" with x: "<<get_x()<<",y: "<<get_y()<<std::endl;}
protected:double get_x() const{return m_x;}double get_y() const{return m_y;}
private:double m_x{0.0};double m_y{0.0};
};
#endif
  • rectangle.cpp
#include "rectangle.h"Rectangle::Rectangle(double x, double y,std::string_view name): Shape(name),m_x(x),m_y(y)
{}
  • square.h
#ifndef SQUARE_H
#define SQUARE_H
#include "rectangle.h"
class Square:public Rectangle{
public:Square() = default;~Square() = default;Square(double x,std::string_view name);void draw() const {std::cout<<"Square Drawing "<<m_name<<" with x: "<<get_x()<<std::endl;}
};
#endif
  • square.cpp
#include "square.h"Square::Square(double x, std::string_view name): Rectangle(x,x,name)
{
}
  • main.cpp
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;// Shape -> Rectangle -> Square
// draw()
void test1() {// 静态绑定的不足Shape s1("Shape1");s1.draw();// Shape Drawing Shape1Rectangle r1(1.0,2.0,"Rectangle1");r1.draw();// Rectangle Drawing Rectangle1 with x: 1,y: 2Square sq1(3.0,"Square1");sq1.draw();// Square Drawing Square1 with x: 3// Base PointerShape* shape_ptr = &s1;shape_ptr->draw();// Shape Drawing Shape1shape_ptr = &r1;shape_ptr->draw();// Shape Drawing Rectangle1shape_ptr = &sq1;shape_ptr->draw();// Shape Drawing Square1
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
  •  执行结果:
PS D:\Work\C++UserLesson\cppenv\static_bind\build> ."D:/Work/C++UserLesson/cppenv/static_bind/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1 with x: 1,y: 2
Square Drawing Square1 with x: 3
Shape Drawing Shape1
Shape Drawing Rectangle1
Shape Drawing Square1
over~
PS D:\Work\C++UserLesson\cppenv\static_bind\build>

第二节:虚函数与动态绑定

>>动态绑定

  • 实现继承
  • 父类、子类需要动态绑定的函数设置为虚函数
  • 创建父类指针/引用(推荐指针)指向子类对象,然后调用

>>虚函数

  • 虚函数是应在派生类中重新定义的成员函数
  • 关键字为virtual

通过例子来实现多态

  • shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include <string>
#include <string_view>
#include <iostream>
class Shape{
public:Shape() = default;~Shape() = default;Shape(std::string_view name);virtual void draw() const {std::cout<<"Shape Drawing "<<m_name<<std::endl;}
protected:std::string m_name;
};
#endif
  • shape.cpp
#include "shape.h"Shape::Shape(std::string_view name) : m_name(name){}
  • rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <string>
#include <string_view>
#include <iostream>
#include "shape.h"
class Rectangle:public Shape{
public:Rectangle() = default;~Rectangle() = default;Rectangle(double x,double y,std::string_view name);virtual void draw() const {std::cout<<"Rectangle Drawing "<<m_name<<","<<"x: "<<get_x()<<",y: "<<get_y()<<std::endl;}
protected:double get_x() const{return m_x;}double get_y() const{return m_y;}
private:double m_x{0.0};double m_y{0.0};
};
#endif
  • rectangle.cpp
#include "rectangle.h"Rectangle::Rectangle(double x, double y,std::string_view name): Shape(name),m_x(x),m_y(y)
{}
  • square.h
#ifndef SQUARE_H
#define SQUARE_H
#include "rectangle.h"
class Square:public Rectangle{
public:Square() = default;~Square() = default;Square(double x,std::string_view name);void draw() const {std::cout<<"Square Drawing "<<m_name<<" with x: "<<get_x()<<std::endl;}
};
#endif
  • square.cpp
#include "square.h"Square::Square(double x, std::string_view name): Rectangle(x,x,name)
{
}
  • 执行结果:
PS D:\Work\C++UserLesson\cppenv\dynamic_bind\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_bind/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_bind\bin>

第三节:多态对象的应用场景与大小

(1)多态的两个应用场景

  • 函数
  • 存储进入Collections

(2)多态与Collection

  • 可以存储值类型(并不满足多态)
  • 可以存储指针类型
  • 不可以存储引用

(3)通过例子来

  • 多态的两大应用场景

 注意:这里的源文件和头文件和第二节的一样!

(1)Base Pointers

#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Base PointersShape* shape_ptr = &s1;draw_shape(shape_ptr);shape_ptr = &r1;draw_shape(shape_ptr);shape_ptr = &sq1;draw_shape(shape_ptr);
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>

 (2)多态与Collection

  • 可以存储值类型(并不满足多态)
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// collection cout<<"*********collection*********"<<endl;Shape shapes[]{s1,r1,sq1}; // 不符合多态for(Shape &s:shapes) {s.draw();}
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
*********collection*********
Shape Drawing Shape1
Shape Drawing Rectangle1
Shape Drawing Square1
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>

(2)多态与Collection

  • 可以存储指针类型
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Pointercout<<"*********Pointer*********"<<endl;Shape* shapes_ptr[]{&s1,&r1,&sq1};for(Shape* s:shapes_ptr) {s->draw();}
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}

执行结果:

PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
*********Pointer*********
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>

 (2)多态与Collection

  • 不可以存储引用
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Shape ref // cout<<"*********collection*********"<<endl;Shape &shape_ref[]{s1,r1,sq1}; //error 不允许使用引用的数组
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}

 

未完待续~

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

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

相关文章

让B端管理软件既美观又实用的解决方案来了

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 让B端管理软件既美观又实用的解决方案来了 在当今数字化时代&#xff0c;B端管理软件已…

安泰ATA-4014高压功率放大器在超声马达驱动电路设计中的应用

本文将与大家分享&#xff0c;ATA-4014高压功率放大器在超声马达驱动电路设计和制作中的应用&#xff0c;希望能对各位工程师有所帮助与启发。 1引言 超声波马达又称超声电机(ultrasonicmotor&#xff0c;简称USM)20世纪80年代才诞生的一种全新概念电机种类.超声电机采用与传统…

华为AC+FIT AP组网配置

AC配置 vlan batch 100 to 101dhcp enableip pool apgateway-list 192.168.100.254 network 192.168.100.0 mask 255.255.255.0 interface Vlanif100ip address 192.168.100.254 255.255.255.0dhcp select globalinterface GigabitEthernet0/0/1port link-type trunkport trun…

马尔可夫预测(Python)

马尔科夫链&#xff08;Markov Chains&#xff09; 从一个例子入手&#xff1a;假设某餐厅有A&#xff0c;B&#xff0c;C三种套餐供应&#xff0c;每天只会是这三种中的一种&#xff0c;而具体是哪一种&#xff0c;仅取决于昨天供应的哪一种&#xff0c;换言之&#…

2024年会是大牛市吗?我有500万想找个证券公司开融资融券账户,哪家券商两融利率最低?

2024年是否会迎来大牛市&#xff0c;这是一个颇具争议的话题。然而&#xff0c;无论市场走势如何&#xff0c;对于有500万的投资者来说&#xff0c;开立一个融资融券账户确实是一个不错的选择。在选择券商时&#xff0c;除了考虑两融利率外&#xff0c;投资者还应该关注券商的服…

10. UE5 RPG使用GameEffect创建血瓶修改角色属性

前面我们通过代码实现了UI显示角色的血量和蓝量&#xff0c;并实现了初始化和在数值变动时实时更新。为了测试方便&#xff0c;没有使用GameEffect去修改角色的属性&#xff0c;而是通过代码直接修改的数值。 对于GameEffect的基础&#xff0c;这里不再讲解&#xff0c;如果需要…

5.列表选择弹窗(BottomListPopup)

愿你出走半生,归来仍是少年&#xff01; 环境&#xff1a;.NET 7、MAUI 从底部弹出的列表选择弹窗。 1.布局 <?xml version"1.0" encoding"utf-8" ?> <toolkit:Popup xmlns"http://schemas.microsoft.com/dotnet/2021/maui"xmlns…

幻兽帕鲁游戏多人联机服务器价格对比:腾讯云VS阿里云VS华为云

《幻兽帕鲁》游戏5天捞金15亿&#xff0c;而且想要多人联机玩游戏&#xff0c;还允许我们自己购买服务器来搭建专属服务器&#xff0c;届时三五好友一起来玩&#xff0c;真的不要太爽啊&#xff01;那么搭建幻兽帕鲁游戏多人联机的服务器需要多少钱&#xff1f;下面boke112百科…

搜索引擎Elasticsearch了解

1.Lucene 是什么? 2.模块介绍 Lucene是什么: 一种高性能,可伸缩的信息搜索(IR)库 在2000年开源,最初由鼎鼎大名的Doug Cutting开发 是基于Java实现的高性能的开源项目 Lucene采用了基于倒排表的设计原理,可以非常高效地实现文本查找,在底层采用了分段的存储模式,使它在读…

【JaveWeb教程】(28)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(1)

目录 SpringBootWeb案例011. 准备工作1.1 需求&环境搭建1.1.1 需求说明1.1.2 环境搭建 1.2 开发规范 2. 部门管理 SpringBootWeb案例01 前面我们已经讲解了Web前端开发的基础知识&#xff0c;也讲解了Web后端开发的基础(HTTP协议、请求响应)&#xff0c;并且也讲解了数据库…

偏差,均方根误差RMSE

目录 一、均方误差MSE​编辑 二、R自定义函数 三、均方根误差(RMSE), 平均绝对误差(MAE), 标准差(Standard Deviation)的对比 参考&#xff1a; 一、均方误差MSE 这里使用trace是因为多元情形下方差是矩阵。 二、R自定义函数 来自&#xff1a;2022 - Biometrical Journal - …

electron-builder vue 打包后element-ui字体图标不显示问题

当使用electron打包完成的时候&#xff0c;启动项目发现使用的element-ui字体图标没显示都变成了小方块&#xff0c;并出现报错&#xff0c;请看下图&#xff1a; 解放方法&#xff1a; 在vue.config.js中设置 customFileProtocol字段&#xff1a;pluginOptions: {electronBui…

单片机之keil软件环境搭建

简介 Keil提供了包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案&#xff0c;通过一个集成开发环境&#xff08;μVision&#xff09;将这些部分组合在一起。     目前软件对中文的支持不友好&#xff0c;不建议安装网上的一些汉化包…

编码神仙插件Machinet AI GPT-4 Chat and Unit Tests

最近发现一个神仙插件Machinet AI GPT-4 Chat and Unit Tests&#xff0c;支持多个编译器安装使用。 我下载安装到Android Studio上&#xff0c;不需要登录直接可以使用。 可以直接提问&#xff0c;支持中文。

学习笔记之 机器学习之预测雾霾

文章目录 Encoder-DecoderSeq2Seq (序列到序列&#xff09; Encoder-Decoder 基础的Encoder-Decoder是存在很多弊端的&#xff0c;最大的问题就是信息丢失。Encoder将输入编码为固定大小的向量的过程实际上是一个“信息有损的压缩过程”&#xff0c;如果信息量越大&#xff0c;…

CentOS网络配置进阶:深入研究network服务和NetworkManager

前言 如果你正在使用CentOS系统,并且想要深入了解网络管理和配置,那么本文肯定适合你!在这篇文章中,作者深入探讨了CentOS中的两种网络管理方式:network服务和NetworkManager。通过详实的讲解和实用的示例,你将会学习到如何使用这两种工具来管理网络接口、配置IP地址、网…

Python基础(二十九、pymsql)

文章目录 一、安装pymysql库二、代码实践1.连接MySQL数据库2.创建表格3.插入数据4.查询数据5.更新数据6.删除数据 三、完整代码示例四、结论 使用Python的pymysql库可以实现数据存储&#xff0c;这是一种连接MySQL数据库的方式。在本篇文章中&#xff0c;将详细介绍如何使用pym…

Android开发修炼之路——(一)Android App开发基础-1

本文介绍基于Android系统的App开发常识&#xff0c;包括以下几个方面&#xff1a;App开发与其他软件开发有什么不一样&#xff0c;App工程是怎样的组织结构又是怎样配置的&#xff0c;App开发的前后端分离设计是如何运作实现的&#xff0c;App的活动页面是如何创建又是如何跳转…

C++:优先队列-Priority_queue

目录 1.关于优先队列 2.priority_queue的使用 1.构造方法 2.empty();判空 3.size(); 4.top(); 5.push(val); 6.pop(); 3.优先队列模拟实现 4.用优先队列解决数组中第K个大的元素 1.关于优先队列 在C中&#xff0c;可以使用STL&#xff08;标准模板库&#xff09;中的p…

【Uni-App】Vuex在vue3版本中的使用与持久化

Vuex是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 简而言之就是用来存数据&#xff0c;可以有效减少使用组件传参出现的问题。 基本元素&#xff1a;…