10、C++面向对象三大特性【高频】

面向对象编程 具有 封装、继承、多态 三个主要特性

  • 封装

    • 将属性和行为作为一个整体、一个类,来表现生活中的事物

    • 将属性和行为加以权限控制,包括public 公共权限、protected 保护权限、private 私有权限这三种,从而让 自己的属性和行为 只让可信的类或对象操作,对不可信的进行隐藏。这样可以防止 外界干扰 或者 不确定性访问

  • 继承

    • 就是指 一个类 可以从 另一个类 中继承 属性和行为,前一个类称为 子类或派生类,后一个类称为 父类或基类。通过继承,子类可以使用父类的代码,并 添加新的功能 或 修改已有的功能,从而减少重复的代码

    • 继承方式一共有三种:公共继承、保护继承、私有继承

    • 一些细节:

      • 访问权限:

      • 注意,继承方式不影响子类对父类的访问!子类对父类的访问只看父类成员的访问权限即可。如下面三种继承方式都能访问父类中的public和protected成员:

        class Teacher : /*public*/ /*protected*/ private Person
        {
        public:Teacher(const string& name, int age, const string& title): Person(name, age), m_title(title){}
        ​void ShowTeacherInfo(){ShowInfo();                             //正确,public属性子类可见cout << "姓名:" << m_name << endl;        //正确,protected属性子类可见//cout << "年龄:" << m_age << endl;       //错误,private属性子类不可见
        ​cout << "职称:" << m_title << endl;   //正确,本类中可见自己的所有成员}
        ​
        private:string  m_title;        //职称
        };

      • 继承权限:

        • 继承方式只是为了控制 子类的调用方(即子类对象)对父类的访问权限,不影响子类本身对父类的访问权限。如果父类的一个函数是public,子类采用是private或protected继承,那么在子类中可以访问这个函数,而子类的对象则无法访问这个函数(子类的对象其实就是外部)

          class Person
          {
          public:...void ShowInfo(){cout << "姓名:" << m_name << endl;cout << "年龄:" << m_age << endl;}
          protected:string  m_name;     //姓名
          private:int     m_age;      //年龄
          };
          ​
          class Teacher : private Person
          {
          public:...void ShowTeacherInfo(){ShowInfo();                          //正确,public属性子类可见cout << "职称:" << m_title << endl;  //正确,本类中可见自己的所有成员}
          private:string  m_title;        //职称
          };
          ​
          void TestPrivate()
          {Teacher teacher("李四", 35, "副教授");teacher.ShowInfo();  //错误,因为Teacher采用了private的继承方式,外部不可访问。cout << endl;teacher.ShowTeacherInfo();
          }

          注:public、protected、private三种继承方式,相当于把父类的public访问权限在子类中变成了对应的权限。 如protected继承,把父类中的public成员在本类中变成了protected的访问控制权限;private继承,把父类的public成员和protected成员在本类中变成了private访问控制权。

      • 继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

      • 成员或函数同名时,如何通过子类对象,访问子类和父类中的成员?

        • 对于子类函数,直接访问即可

        • 对于父类函数,需要再加上父类作用域

        class Base {
        public:Base(){m_A = 100;}
        ​void func(){cout << "Base - func()调用" << endl;}
        ​void func(int a){cout << "Base - func(int a)调用" << endl;}
        ​
        public:int m_A;
        };
        ​
        ​
        class Son : public Base {
        public:Son(){m_A = 200;}
        ​
        //当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数,包括func(int a)
        //如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域void func(){cout << "Son - func()调用" << endl;}
        public:int m_A;
        };
        ​
        void test01()
        {Son s;
        ​cout << "Son下的m_A = " << s.m_A << endl;cout << "Base下的m_A = " << s.Base::m_A << endl;//加作用域
        ​s.func();s.Base::func();//加作用域s.Base::func(10);//加作用域
        ​
        }
        • 另外:

          • 如果是静态成员同名的话,处理方法也一样

          • 多继承中,如果不同父类中出现了同名情况,子类使用时候要加作用域

      • 菱形继承:两个派生类继承同一个基类,又有某个类同时继承者两个派生类。

        class Animal
        {
        public:int m_Age;
        };
        ​
        //继承前加virtual关键字后,变为虚继承
        //此时公共的父类Animal称为虚基类
        class Sheep : virtual public Animal {};
        class Tuo   : virtual public Animal {};
        class SheepTuo : public Sheep, public Tuo {};
        ​
        void test01()
        {SheepTuo st;st.Sheep::m_Age = 100;st.Tuo::m_Age = 200;
        ​cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;cout << "st.m_Age = " << st.m_Age << endl;
        }
        ​
        ​
        int main() {
        ​test01();
        ​return 0;
        }
        • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义

        • 利用虚继承可以解决菱形继承问题

  • 多态

    • 多态分为两类

      • 静态多态:函数重载 和 运算符重载 属于静态多态,复用函数名。静态多态的函数地址早绑定,在编译阶段就已经确定了函数地址

      • 动态多态:即运行时多态,通过 派生类 和 虚函数 实现。动态多态的函数地址晚绑定,在运行阶段才确定函数地址

    • 实现多态须同时满足的条件:

      1. 有继承关系

      2. 子类重写父类中的虚函数

    • 使用多态须满足的条件

      • 父类指针或引用指向子类对象

      class Animal
      {
      public://Speak函数就是虚函数//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。virtual void speak(){cout << "动物在说话" << endl;}
      };
      ​
      class Cat :public Animal
      {
      public:void speak(){cout << "小猫在说话" << endl;}
      };
      ​
      class Dog :public Animal
      {
      public:
      ​void speak(){cout << "小狗在说话" << endl;}
      ​
      };
      //我们希望传入什么对象,那么就调用什么对象的函数
      //如果函数地址在编译阶段就能确定,那么静态联编
      //如果函数地址在运行阶段才能确定,就是动态联编
      void DoSpeak(Animal & animal)
      {animal.speak();
      }
      //
      //多态满足条件: 
      //1、有继承关系
      //2、子类重写父类中的虚函数
      //多态使用:
      //父类指针或引用指向子类对象
      void test01()
      {Cat cat;DoSpeak(cat);Dog dog;DoSpeak(dog);
      }
      int main() {test01();return 0;
      }
    • 一些细节:

      • 纯虚函数:

        • 在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写内容。因此可以将虚函数改为纯虚函数

        • 纯虚函数语法:

          virtual 返回值类型 函数名 (参数列表)= 0 ;
        • 当类中有了纯虚函数,这个类也称为抽象类,它的特点:

          1. 无法实例化对象

          2. 子类必须重写抽象类中的纯虚函数,否则也属于抽象类

          class Base
          {
          public://纯虚函数//类中只要有一个纯虚函数就称为抽象类//抽象类无法实例化对象//子类必须重写父类中的纯虚函数,否则也属于抽象类virtual void func() = 0;
          };
          ​
          class Son :public Base
          {
          public:virtual void func() {cout << "func调用" << endl;};
          };
          ​
          void test01()
          {Base * base = NULL;//base = new Base; // 错误,抽象类无法实例化对象base = new Son;base->func();delete base;//记得销毁
          }
          ​
          int main() {test01();return 0;
          }
      • 虚析构和纯虚析构

        • 多态使用时,如果子类中有属性开辟到堆区,父类指针如何调用子类的析构函数?

          答:将父类中的析构函数改为虚析构或者纯虚析构,这样当delete 父类指针时,就可以将子类的数据彻底清除干净了,从而防止内存泄漏

        • 虚析构和纯虚析构共性:

          1. 可以用父类指针 调用子类的析构函数,从而释放子类对象

          2. 都需要有具体的函数实现

        • 虚析构和纯虚析构区别:

          • 如果是纯虚析构,该类属于抽象类,无法实例化对象

        • 虚析构语法:

          virtual ~类名(){}

          纯虚析构语法:

          virtual ~类名() = 0;
          类名::~类名(){}
        class Animal {
        public:Animal(){cout << "Animal 构造函数调用!" << endl;}virtual void Speak() = 0;//在析构函数加上virtual关键字,变成虚析构函数//virtual ~Animal()//{//  cout << "Animal虚析构函数调用!" << endl;//}virtual ~Animal() = 0;
        };
        ​
        Animal::~Animal()
        {cout << "Animal 纯虚析构函数调用!" << endl;
        }
        ​
        class Cat : public Animal {
        public:Cat(string name){cout << "Cat构造函数调用!" << endl;m_Name = new string(name);}virtual void Speak(){cout << *m_Name <<  "小猫在说话!" << endl;}~Cat(){cout << "Cat析构函数调用!" << endl;if (this->m_Name != NULL) {delete m_Name;m_Name = NULL;}}
        public:string *m_Name;
        };
        ​
        void test01()
        {Animal *animal = new Cat("Tom");animal->Speak();//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏//怎么解决?给基类增加一个虚析构函数//虚析构函数就是用来解决通过父类指针释放子类对象delete animal;
        }
        int main() {test01();return 0;
        }
        • 另外,如果子类中没有堆区数据,父类中可以不写虚析构或纯虚析构

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

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

相关文章

探索浮点数在内存中的存储(附带快速计算补码转十进制)

目录 一、浮点数在内存中的存储 1、常见的浮点数&#xff1a; 2、浮点数存储规则&#xff1a; 3、内存中无法精确存储&#xff1a; 4、移码与指数位E&#xff1a; 5、指数E的三种情况&#xff1a; 二、快速计算补码转十进制 1、第一种方法讨论&#xff1a; 2、第二种方…

Windows版FFmpeg使用及B站视频下载示例python源码

Windows版FFmpeg使用及B站视频下载示例python源码 FFmpeg介绍和下载 FFmpeg 是一个功能强大、灵活且广泛使用的多媒体处理工具&#xff0c;无论是在专业领域还是日常使用中&#xff0c;都能满足各种多媒体处理需求。FFmpeg 是一个开源项目&#xff0c;遵循 LGPL 或 GPL 许可。…

最新版 (持续更新)docker 加速源 linux yum 源

收藏两个网站&#xff0c;配置docker 加速源与yum 源。 docker 加速源链接 Docker/DockerHub 国内镜像源/加速列表&#xff08;2月25日更新-长期维护&#xff09;-腾讯云开发者社区-腾讯云https://cloud.tencent.com/developer/article/2485043 yum 源 CentOS7停服后yum源配置…

计算机三级网络技术备考(2)

#第二章关于中小型网络系统总体规划与设计方法 考点一&#xff1a;网络总体设计 考点二网络关键设备选型 考点三服务器的选型 #第三章&#xff1a;IP地址规划设计技术 考点1&#xff1a;二进制和十进制转换 小练习记得做昂 考点2&#xff1a;IP地址分类及规划方法 A类&#x…

【代码软件 | vs2019】vs2019+Qt5.12.12开发环境 的下载、安装详细介绍

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

【DeepSeek探索篇(四)】高效学习与工作,从搭建DeepSeek个人知识库开始!

高效学习与工作&#xff0c;从搭建DeepSeek个人知识库开始&#xff01; 打工人和学习者必看&#xff01;你为何急需一个个人知识库&#xff1f;搭建个人知识库需要用到哪些技术呢&#xff1f;一、模型微调与RAG技术简介二、RAG技术原理剖析 揭秘Embedding&#xff1a;为何它是D…

AI数字人系统源码部署解决方案!!!

一、开场白 如今&#xff0c;科技的步伐越来越快&#xff0c;数字人已经从想象中走进了我们的现实生活。它们在娱乐、教育、医疗等多个领域大放异彩。了解数字人的代码开发技术&#xff0c;能让我们更好地理解其工作原理&#xff0c;为那些想在这一领域大展拳脚或者用数字人技…

【网络】HTTPS协议原理

文章目录 1. HTTPS 是什么2. 常见的加密方式3. 数据摘要4. 加密方案测试4.1 只是用对称加密4.2 只使用非对称加密4.3 双方都使用非对称加密4.4 对称 非对称 5. 证书5.1 数据签名5.2 CA 证书5.3 方案五 非对称加密 对称加密 证书认证 1. HTTPS 是什么 HTTP 协议内容都是按照…

计算机网络————(三)

前文二 前文一 Websocket协议 是一种存在TCP协议之上的协议 当客户端需要了解服务器是否更新就需要不断给客户端发送请求询问是否更新&#xff0c;这行会造成服务端压力很大 而Websocket相当于服务器一旦更新了就会给客户端发送消息表明自己更新了&#xff0c;类似客户端订阅…

Blueprint —— Events

目录 一&#xff0c;Event Level Reset 二&#xff0c;Event Actor Begin Overlap 三&#xff0c;Event Actor End Overlap 四&#xff0c;Event Hit 五&#xff0c;Event Any Damage 六&#xff0c;Event Point Damage 七&#xff0c;Event Radial Damage 八&#xff…

博云先进算力管理平台AIOS已上线全尺寸DeepSeek系列模型

在异构基础设施上轻松运行全尺寸DeepSeek DeepSeek于2024年12月发布了包括 DeepSeek V3、R1、Janus Pro等多版本模型。V3版本适用于通用型自然语言处理任务&#xff0c;R1专注于复杂推理任务&#xff0c;而 Janus Pro 则擅长多模态理解与生成&#xff0c;可满足企业不同 AI 场…

如何搭建起成熟的团队知识文档管理系统

搭建一个成熟的团队知识文档管理系统&#xff0c;对于提升团队的工作效率、促进信息共享以及保障知识资产的安全性都至关重要。**要实现这一目标&#xff0c;首先需要明确知识管理的目标和需求&#xff0c;其次选择合适的知识管理工具&#xff0c;最后制定有效的管理流程和权限…

0-基于强化学习的图Transformer算法求解车辆路径问题(2023)

文章目录 Abstract1 Introduction2. Related Work2.1 引言2.2.基于RNN的VRP解决方案2.3.基于GNN的VRP解决方案2.4.基于Transformer的车辆路径问题求解方法3 边嵌入注意力模型3.1 编码器3.1.1 边嵌入多头注意力3.1.2. 前馈网络(FFN)、批量归一化和残差连接3.2 解码器3.2.1 解码…

C#快速调用DeepSeek接口,winform接入DeepSeek查询资料 C#零门槛接入DeepSeek C#接入DeepSeek源代码下载

下载地址<------完整源码 在数字化转型加速的背景下&#xff0c;企业应用系统对智能服务的需求日益增长。DeepSeek作为先进的人工智能服务平台&#xff0c;其自然语言处理、图像识别等核心能力可显著提升业务系统的智能化水平。传统开发模式下&#xff0c;C#开发者需要耗费大…

有关与 WSL 2 的主要区别的信息,请访问 https://aka.ms/wsl2

https://learn.microsoft.com/zh-cn/windows/wsl/install-manual#step-4—download-the-linux-kernel-update-package

深度神经网络(DNN)编译器原理简介

深度神经网络(DNN)编译器原理简介 目录 深度神经网络(DNN)编译器原理简介1 什么是DNN编译器2 前端3 后端4 中间表达&#xff08;Intermediate Representation&#xff0c;后文用IR代替&#xff09;5 优化过程6 计算图优化6.1 表达式化简6.2 公共子表达式消除6.3 常数传播6.4 矩…

最小二乘法与梯度下降(原理)

一、最小二乘法 损失函数矩阵形式&#xff1a; 令导数loss0 &#xff0c;可解得&#xff1a; API : sklearn.linear_model.LinearRegression() 功能&#xff1a; 普通最小二乘法线性回归, 权重和偏置是直接算出来的&#xff0c;对于数量大的不适用&#xff0c;因为计算量…

【2025全网最新最全】前端Vue3框架的搭建及工程目录详解

文章目录 安装软件Node.js搭建Vue工程创建Vue工程精简Vue项目文件 Vue工程目录的解读网页标题的设置设置全局样式路由配置 安装软件Node.js 下载地址&#xff1a;https://nodejs.org/zh-cn/ 安装完成后&#xff0c;打开cmd,查看环境是否准备好 node -v npm -vnpm使用之前一定…

Java 之集成 DataX 数据同步工具

1、官网下载 DataX https://github.com/alibaba/DataX 2、将依赖添加到本地&#xff08;DataX没有maven坐标&#xff0c;需要自己安装&#xff09; mvn install:install-file -Dfile"datax-common-0.0.1.jar" "-DgroupIdcom.datax" "-DartifactIdda…

OpenEuler学习笔记(三十五):搭建代码托管服务器

以下是主流的代码托管软件分类及推荐&#xff0c;涵盖自托管和云端方案&#xff0c;您可根据团队规模、功能需求及资源情况选择&#xff1a; 一、自托管代码托管平台&#xff08;可私有部署&#xff09; 1. GitLab 简介: 功能全面的 DevOps 平台&#xff0c;支持代码托管、C…