CPP_类和对象

面向对象:

更接近真实世界(关注各对象之间的关系,而非各步骤的进行)


  • 将结构体升级成立类

  • 类里面可以有:成员函数,成员变量

  • class Stack {
    public:void Init(int defaultCapacity=4 ) {_a = (int*)malloc(sizeof(int) * defaultCapacity);_capacity = defaultCapacity;_top = 0;}void Push(int x) {_a[_top++] = x;}void Destory() {free(_a);_a = nullptr;}
    private:int* _a;int _top;int _capacity;
    };
    int main() {Stack st;st.Init();st.Push(1);st.Destory();return 0;
    }
    
  • 访问限定符(即访问权限):

    • public:类外可以访问
    • protected
    • private
    • 每一种访问限定符的作用域是从当前限定符到下一个限定符
  • 一个类里面的函数,也可以声明与定义分离(如果函数太长了话)(如果声明和定义都直接写在类里面,如果这些函数符合内联规则,则默认都是内联函数

  • //stack.c
    class Stack {
    public:void Init(int defaultCapacity=4);void Push(int x) {a[top++] = x;}
    }
    
  • //stack.h
    //指定类域
    void Stack::Init(int defaultCapacity=4 ) {a = (int*)malloc(sizeof(int) * defaultCapacity);capacity = defaultCapacity;top = 0;
    }
    

封装
  • 本质上是一种更好的管理(便于用户使用类)

  • 对于成员变量,只有在实例化某一个类的时候,才会为类里面的成员变量开辟空间(即它的定义)(也就相当于类其实是一种设计,并没有实际的东西,只有实例化之后,才有这种设计对应的实例)

  • class Stack {
    private:int* _a;int _top;int _capacity;/*这些变量是声明,不是定义(对于变量来说,是否开空间是区分声明和定义的最大区别)所以在实例化对象的时候,才定义这些变量*/
    };
    
  • 对于某一个类的实例化对象来说,sizeof() 计算的是成员变量在经过内存对齐之后的总大小,不加成员函数。(因为对于每一个实例来说,都有一套成员变量都是单独属于它们自己的。但对于成员函数来说,所有实例的该方法都是一样的,没有必要每个实例都存储一份成员函数,只需要在一个公用区域存一份,所有实例都访问这一个就行了,所以sizeof()只有成员变量,没有成员函数)

  • 如果一个类只有成员函数,或者什么都没有,sizeof() 的计算结果是1。相当于这个类的对象默认占一个字节,相当于占一个位置,表示这个对象是存在的,但不存有效数据


This指针
  • 其实对于实例化对象来说,虽然成员函数是共用的,但每个实例调用时都是使用自己的成员变量的值,其实本质上是因为编译器默认使用了this指针,将当前实例的地址传给了成员函数,所以不同实例在调用的时候,使用的是自己的成员变量

  • class Date { 
    public:void print() {cout << year << " " << mon << " " << day;}void init() {year = 1;mon = 2;day = 3;}
    private:int year;int mon;int day;
    };
    int main() {Date d;d.init();d.print();return 0;
    }
    /*本质上其实是将当前实例的地址传给了成员函数,所以不同实例在调用的时候,使用的是自己的成员变量void print(Date* this) {cout << this->year << " " << this->mon;}Date d;d.print(&d);
    */
    
  • this不能在形参和实参传递,但可以直接在函数内部使用

  • this指针是形参,所以和普通参数一样,是存在栈里面的,作为栈帧的一部分(随压栈一起)


类的六大默认成员函数(不显式写出编译器就会自行生成)
  • 一.构造函数(完成实例的初始化):

    • 函数名与类名相同

    • 无返回值(也不需要写void)

    • 在对象实例化的时候编译器自动调用对应的构造函数(如果不写构造函数,则编译器会自动生成默认的构造函数)

    • 构造函数可以重载(多种初始化的方式)

    • 没有自己写的构造函数时,编译器生成默认的构造函数,这个函数针对内置类型不做处理,针对自定义类型成员,会去调用该类型的构造函数(而对于成员变量的声明,可以给默认参数,本质上就是给这个自动生成的构造函数使用的

    • **默认构造函数(无参构造函数,全缺省构造函数,没有构造函数时编译器默认生成的构造函数)**最多只能有一个,也可以没有(如果没有,那就不能用默认方式初始化)如果当自己写了别的不是默认构造函数形式的构造函数,那就需要自己在写一个默认构造函数

    • 有两种情况不需要自己写构造函数:

      • 内置类型成员都有缺省值,且初始化符合我们的要求
      • 全是自定义类型的数据,且这些类型都有自己的默认构造函数
    • class stack {
      public:stack(int capacity=4) {_a = (int*)malloc(sizeof(int) * capacity);_capacity = 0;_top = 0;}private:/*给的是缺省值,是给编译器的默认构造函数用的,这里并没有开辟空间,在实例化的时候才会开辟空间*/int* _a=nullptr;int _capacity=1;int _top=1;
      };
      

  • 二.析构函数(相当于destroy)(完成对象中资源的清理工作,即free等,为了防止编译器直接销毁对象造成内存泄露):

    • 在类名前加上~

    • 无返回值无参数

    • 不可以重载

    • 编译系统自动调用

    • 不写析构函数,编译器会自动生成(这个函数针对内置类型不做处理,针对自定义类型成员,会去调用该类型的析构函数)

    • 有动态申请的资源,就需要自己写析构函数(因为普通的变量会在函数本身创建的栈上,随函数结束栈的销毁而销毁了,所以只有在堆区或其他区上有自行申请的资源才需要析构)

    • class stack {
      public:~stack() {free(_a);_a = nullptr;_capacity = 0;_top = 0;}
      private:int* _a;int _capacity;int _top;
      };
      

  • 三.拷贝构造

    • 是一种构造函数的特殊重载形式,相当于传一个同类型的变量作为参数

    • 在传参时,必须以引用的方式传递参数,不然会发生无限递归

    • 因为如果以传值调用来传递参数,本质上来说其实是要调用该类型的拷贝构造函数来创建形参的,也就相当于对于内置数据类型形参是直接拷贝,而自定义数据类型则是调用拷贝构造函数来创建形参的

    • class Date {
      public:Date(const Date & d) {_year = d._year;_mon = d._mon;_day = d._day ;}
      private:int _year = 1;int _mon = 1;int _day = 1;
      };
      
    • 虽然_year这些成员属性是私有的,但私有属性只有在类外不能访问,此时在类内,是可以访问的

    • 如果不显式定义,编译器会自己生成默认拷贝构造函数,默认是:

      • 内置数据类型完成值拷贝/浅拷贝
      • 自定义数据类型会调用它的拷贝构造函数
    • 在有些场景下,浅拷贝不足以满足要求,就需要自己写拷贝构造函数,以实现深拷贝(比如在stack里,如果进行浅拷贝,那么会使两个栈里面的数组指针指向同一块空间(因为浅拷贝只将数值原封不动的拷贝过去,所以它们指向同一块空间),显然不是我们想要的)


  • 四.赋值运算符重载

    • 用于已经存在的两个对象之间的赋值拷贝

    • 本质就是将赋值运算符重载了一下

    • 如果不显式定义,编译器会自己生成默认赋值运算符重载,默认是:

        • 内置数据类型完成值拷贝/浅拷贝
        • 自定义数据类型会调用它的赋值运算符重载
      • 赋值运算符只能定义在类内部,不能重载成全局函数。(别的运算符既可以重载在类内,也可以重载成全局,但由于赋值运算符重载是一种默认成员函数,所以只能在类内)
    • class Date {
      public:Date& operator= (Date& x) {_day = x._day;return *this;}
      //之所以返回值是一个(Date&),是为了支持连续赋值的情景,如果不要求支持连续赋值,则返回值可以写成void
      private:int _year = 1;int _mon = 1;int _day = 1;
      };int main() {Date d1(1);Date d2(2);Date d3(3);d3 = d1 = d2;return 0;
      }
      

  • 五.取地址运算符的重载

  • Date* Date::operator& () {return this;
    }
    const Date* Date::operator& () const {return this;
    }//这两个函数因为参数不同构成函数重载
    

  • const

    • 对应一些成员实例,如果是const修饰的,那么在使用一些成员函数的时候可能会造成权限的放大,从而导致错误

    • 下面这个代码里,如果print函数右侧不加const,则无法正常打印,因为此时d1的类型是const Date ,而且指向该对象的指针this是隐式传递的,类型是Date* 由于它的类型是编译器底层传递的,我们不能显式来写出this,所以只能将const写在最右边,其实本质就是修饰this指针的

    • void print() const//修饰this指针的const
      {cout << _year<<"--"<<_mon<<"--"<<_day << endl;
      }const Date d1(2023, 1, 26);
      d1.print();
      

在谈构造函数
  • 第一种:构造函数体赋值

  • Date::Date(int year, int mon, int day) {_year = year;_mon = mon;_day = day;
    }
    
  • 第二种:初始化列表

    • 有三类成员变量必须用初始化列表初始化:
      • 没有默认构造函数的结构体变量
      • 引用类型
      • const修饰的变量
    • 对于初始化列表的理解:在实例化对象时相当于时整个对象的定义,而对于它的成员变量,其实是在初始化列表所在的位置定义的,因为引用和const修饰的变量只有在定义的时候才能赋值,所以它们只能在初始化列表里面初始化。其实在初始化列表里,如果不写出所有成员变量,那么就是自定义类型调用默认构造函数,内置类型不做处理(其实内置类型的成员变量在声明的时候给的默认值,就是传到初始化列表里,用于内置类型成员变量初始化的。)它下面的那个{},是为了某些多步初始化的过程无法在初始化列表里完成,需要在{}里完成
    • 成员变量的初始化顺序是按类中的声明顺序初始化的,和其在初始化列表里的顺序无关
  • Date(int year, int mon, int day):_year(year), _mon(mon), _day(day)
    {}
    

explicit 关键字
  • 如果构造函数在传参的时候不想让其发生隐式类型转换,就可以在函数名之前加上explicit

静态成员,函数
  • 静态成员变量是属于这个类的,生命周期是全局的。而普通的成员变量是属于该类的实例的。也就是说静态成员变量是所有实例共享的变量。
  • 静态成员变量没有初始化列表,所以静态成员变量必须在类外边,全局位置定义。(本质上相当于用类去封装全局变量)
  • 静态成员函数:没有this指针,只要指定类域和访问限定符即可访问。静态成员函数只能访问静态成员变量,因为它没有this指针,没法访问某一个实例的普通成员变量
  • 非静态函数可以访问静态成员变量,静态函数不可以访问静态成员变量,函数(因为静态函数没有this指针)
class A {
public:static int _a;
private:
};int A::_a = 0;int main() {A aa;cout << ++A::_a << endl;cout << A::_a << endl;return 0;
}
-------------------------------------------------------------
-------------------------------------------------------------   
class A {
public:static int Get() {return _a;}
private:static int _a;
};int A::_a = 0;int main() {A aa;cout << aa.Get() << endl;cout << A::Get() << endl;return 0;
}

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

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

相关文章

极狐GitLab 如何撤销变更?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 还原更改 (BASIC ALL) 在极狐GitLab 中&#xff0c;您可以还原单个提交或整个合并请求。 当您在 Git 中还原一个提交时&…

PNG透明免抠设计素材大全26000+

在当今的数字设计领域&#xff0c;寻找高质量且易于使用的素材是每个设计师的日常需求。今天&#xff0c;我们将为大家介绍一个超全面的PNG透明免抠设计素材大全&#xff0c;涵盖多种风格、主题和应用场景&#xff0c;无论是平面设计、网页设计还是多媒体制作&#xff0c;都能轻…

uniapp小程序使用echarts

1、引入插件 在Dcloud插件市场下载echarts插件&#xff1a;插件地址 2、页面使用简单示例&#xff1a; <template><view class"pie-view flex-center"><view style"width: 100%; height: 600rpx"><l-echart ref"chartRef&quo…

7-1 三种语言的单词转换

编写程序实现&#xff1a;首先从键盘输入若干个中文与英文单词的偶对&#xff0c;以空行作结束标记&#xff1b;再输入若干个英文与丹麦文单词的偶对&#xff0c;以空行作结束标记。然后输入一个中文单词&#xff0c;输出对应的丹麦文单词&#xff1b;若不存在该单词&#xff0…

开源AI守护童心——幼儿跌倒报警系统的智能安全革命

幼儿园是孩子们成长的乐园&#xff0c;但跌倒事件却时常让家长和园方忧心。教室、走廊、操场&#xff0c;幼儿的每一次意外跌倒都可能带来安全隐患。传统人工监管难以全天候覆盖&#xff0c;反应速度也常受限。如何让幼儿园更安全、更放心&#xff1f;幼儿跌倒报警系统&#xf…

Halcon应用:相机标定

提示&#xff1a;若没有查找的算子&#xff0c;可以评论区留言&#xff0c;会尽快更新 Halcon应用&#xff1a;相机标定 前言一、Halcon应用&#xff1f;二、应用实战1、图像理解1.1、开始标定 前言 本篇博文主要用于记录学习Halcon中算子的应用场景&#xff0c;及其使用代码和…

Arduino示例代码讲解:Project 08 - Digital Hourglass 数字沙漏

Arduino示例代码讲解:Project 08 - Digital Hourglass 数字沙漏 Project 08 - Digital Hourglass 数字沙漏程序功能概述功能:硬件要求:输出:代码结构全局变量`setup()` 函数`loop()` 函数计时和点亮LED:读取倾斜开关状态:重置LED和计时器:运行过程注意事项Project 08 - …

《计算机视觉度量:从特征描述到深度学习》—深度学习图像特征工程

传统算法的图像特征分析和描述&#xff0c;一直贯穿图像算法的发展。2017年深度学习的出现&#xff0c;很多开发人员和技术人员认为&#xff0c;图像特征分析这个概念可以被深度学习完全取代。很长一段时间以深度学习为主的视觉方案成为主流&#xff0c;逐渐淡化了传统视觉的特…

零部件三维激光扫描检测

制造业竞争激烈&#xff0c;零部件的精准检测与三维数据的高效获取&#xff0c;已成为企业确保产品质量、提升生产效率的核心要素。传统检测手段&#xff0c;往往因效率低下、精度不足&#xff0c;难以满足复杂零部件的检测需求。 传统零部件检测&#xff0c;检测人员通常是手…

KafkaSpark

Kafka Kafka基本概念 卡夫卡是一个分布式、分布订阅的消息系统&#xff0c;作为消息中间件使用。 设计上是一个分布式的、分区的和可复制的提交日志服务。 Kafka的优势 分布式系统&#xff0c;易于扩展。 高吞吐量&#xff0c;支持发布和订阅模式。 支持多地复制&#xff…

图文结合 - 光伏系统产品设计PRD文档 -(慧哥)慧知开源充电桩平台

光伏系统产品设计PRD文档 ‌版本号‌&#xff1a;1.0 ‌修订日期‌&#xff1a;2023年10月 ‌作者‌&#xff1a; 一、文档概述 1.1 背景与目标 ‌行业背景‌&#xff1a;全球光伏装机量年增长20%&#xff0c;数字化运维需求迫切‌用户痛点‌&#xff1a;现有系统存在数据延…

Eyecare-100K:首个覆盖多模态、多任务的高质量眼科视觉指令数据集

2025-04-18 , 由浙江大学、哈尔滨工业大学、郴州市第一人民医院、新加坡国立大学等机构合作创建了 Eyecare-100K数据集&#xff0c;这是首个涵盖多种模态、任务和疾病的高质量眼科视觉指令数据集&#xff0c;为眼科智能诊断领域提供了关键资源&#xff0c;推动了医学视觉语言模…

CoT-Drive:利用 LLM 和思维链提示实现自动驾驶的高效运动预测

25年3月来自澳门大学和 MIT 的论文“CoT-Drive: Efficient Motion Forecasting for Autonomous Driving with LLMs and Chain-of-Thought Prompting”。 准确的运动预测对于安全的自动驾驶 (AD) 至关重要。本研究提出 CoT-Drive&#xff0c;这是一种利用大语言模型 (LLM) 和思…

[FPGA基础] RAM篇

Xilinx FPGA RAM 使用指南 1. 引言 随机存取存储器&#xff08;RAM&#xff09;是 Xilinx FPGA 设计中用于存储和快速访问数据的重要资源。Xilinx FPGA 提供多种 RAM 类型&#xff0c;包括块 RAM&#xff08;Block RAM&#xff09;和分布式 RAM&#xff08;Distributed RAM&a…

Elasticsearch内核探秘:从Shard分配到网络通信的深度实践指南

#作者&#xff1a;孙德新 文章目录 一、底层模块深入解析之shard allocation1、shard allocation的介绍2、cluster level shard allocation介绍3、disk-based shard allocation介绍4、shard allocation awareness5、shard allocation filtering6、node下线时的shard延迟分配7、…

SQL Server 2022 常见问题解答:从安装到优化的全场景指南

SQL Server 2022 作为微软最新的数据库管理系统&#xff0c;在性能、安全性和云集成方面带来了多项革新。然而&#xff0c;用户在实际使用中仍可能遇到各类问题。本文将围绕安装配置、性能优化、备份恢复、安全设置、高可用性方案、兼容性问题及错误代码解析等核心场景&#xf…

57、Spring Boot 最佳实践

Spring Boot 最佳实践 一. 开发规范与代码风格 编写高质量的代码不仅需要功能的实现,还需要遵循一定的规范和代码风格,以提高代码的可读性、可维护性和协作效率。以下是 Spring Boot 开发中的一些关键规范和代码风格建议。 1. 代码命名规范 在编写代码时,命名是非常重要的…

​​OSPF核心机制精要:选路、防环与设计原理​

一、OSPF选路规则解析 OSPF作为经典的链路状态路由协议&#xff0c;其选路规则采用层次化优先级机制&#xff0c;不同路由类型遵循严格比较顺序&#xff1a; 1. 路由类型优先级 优先级路由类型描述1域内路由通过1类、2类LSA生成2域间路由通过3类LSA生成3域外路由通过5类/7类…

1.1软考系统架构设计师:系统架构的定义与作用 - 超简记忆要点、知识体系全解、考点深度解析、真题训练附答案及解析

超简记忆要点 定义&#xff1a;结构决策 | 抽象概念 | 多视图模型&#xff08;逻辑/物理/动态&#xff09;作用&#xff1a;解耦复杂需求 | 集成扩展 | 指导开发&#xff08;蓝图&#xff09;要素&#xff1a;构件&#xff08;原子/复合&#xff09; | 连接件&#xff08;API/…

网络socks 代理

在系统/终端中设了这样的环境变量&#xff0c;而没有在代码中覆盖&#xff0c;HTTPX 就会启用该 socks 代理。 env | grep proxy https_proxyhttps://proxyhk.zte.com.cn:80 http_proxyhttp://proxyhk.zte.com.cn:80 no_proxylocalhost,127.0.0.0/8,::1,zte.com.cn,zte.intra,…