C++编程(四) —— OOP

文章目录

  • 前言
  • 一、this指针
  • 二、构造和析构
  • 三、深拷贝浅拷贝
    • 浅拷贝
    • 深拷贝
  • 编程实践


前言

什么是OOP思想?

OOP语言的四大特征:
抽象,封装/隐藏,继承,多态

一、this指针

this指针=》类=》很多对象
一套成员方法是如何处理多个对象的?具体而言:

成员方法show() => 怎么知道处理哪个对象的信息? 答:具体对象的this指针。
成员方法init (name,price,amount) => 怎么知道把信息初始化给哪一个对象的? 答:具体对象的this指针。
类的成员方法一经编译,所有的方法参数,都会加一个this指针,接收调用该方法的对象的地址。

当有一实例化对象good1,good1调用成员方法show时,编译器会自动加入参数:
show(&good1);
当有一实例化对象good2,good2调用成员方法init时,编译器会自动加入参数:
init(&good2,name,price,amount);

二、构造和析构

OOP实现顺序栈。

要想实现一个类,共有一般放成员方法,私有一般放成员变量。
因为顺序栈要实现内存的扩充,所以需要使用数组指针。

class SeqStack
{
public:// 构造函数 SeqStack(int size = 10){cout << " SeqStack() Ptr" << this << endl;_pstack = new int[size];_top = -1;_size = size;}// 自定义的拷贝构造函数 《= 对象的浅拷贝现在有问题了SeqStack(const SeqStack &src){cout << "SeqStack(const SeqStack &src)" << endl;_pstack = new int[src._size];for (int i = 0; i <= src._top; ++i){_pstack[i] = src._pstack[i];}_top = src._top;_size = src._size;}// 析构函数~SeqStack() {cout << this << " ~SeqStack()" << endl;delete[]_pstack;_pstack = nullptr;}void push(int val){if (full()) resize();  // resize不想要用户调他_top++;_pstack[top] = val;}void pop(){if (empty()) return;--_top;}int top() { return _pstack[_top]; }bool empty() { return _top == -1; }bool full() { return _top == _size - 1; }private:int *_pstack;   // 动态开辟数组,存储顺序栈的元素int _top;		// 指向栈顶元素的位置int _size;		// 数组扩容的总大小void resize(){int *ptmp = new int[_size * 2];for (int i = 0; i < _size; ++i){ptmp[i] = _pstack[i];} // memcpy(ptmp, _pstack, sizeof(int)*_size); reallocdelete[]_pstack;_pstack = ptmp;_size *= 2;}
}

析构函数如果需要释放一个指向数组的指针,需要中括号[]

delete[]_pstack;

调用:

SeqStack ps1;  // .data段开辟内存,程序结束才进行析构
int main() 
{SeqStack *ps2 = new SeqStack(60);   //heap段开辟内存ps2->push(70);ps2->pop();cout << ps2->top() << endl;delete ps2;  // 1、在stack段开辟内存  2、调用构造SeqStack ps3;
}

调用总结:
1、全局对象
全局对象定义时进行构造,程序结束才析构。
2、heap段对象
new时:1、malloc内存开辟;2、构造函数。
delete时:1、析构函数;2、free(ps2)
3、stack段对象
定义时构造,出作用域析构。

三、深拷贝浅拷贝

浅拷贝

内存的拷贝

int main() 
{SeqStack s1(10);SeqStack s2 = s1;   // #1SeqStack s3(s1);    // #2// #1和#2都是调用拷贝构造// #1相当于 s2.operator=(s1)// void operator=(const SeqStack& src)
}

在这里插入图片描述
什么时候不能浅拷贝:
对象中的成员变量指针,指向了对象外的资源。所以在浅拷贝时,两个对象的指针就指向了同一块资源

深拷贝

当对象占用外部资源时,使用深拷贝,使得其各自占有各自的资源。
在这里插入图片描述

class SeqStack
{
public:// 构造函数 SeqStack(int size = 10) {}// 自定义的拷贝构造函数 《= 对象的浅拷贝现在有问题了SeqStack(const SeqStack &src){cout << "SeqStack(const SeqStack &src)" << endl;_pstack = new int[src._size];for (int i = 0; i <= src._top; ++i){_pstack[i] = src._pstack[i];}_top = src._top;_size = src._size;}void operator= (const SeqStack &src){if(this == &src) return;  // 防止自赋值delele[] _pstack;  // 重要,需要先释放当前对象的内存_pstack = new int[src.size];for (int i = 0; i <= src._top; ++i){_pstack[i] = src._pstack[i];}_top = src._top;_size = src._size;}// 析构函数~SeqStack() {}void push(int val){}void pop(){}int top() {}bool empty() {}bool full() {}
private:int *_pstack;   // 动态开辟数组,存储顺序栈的元素int _top;		// 指向栈顶元素的位置int _size;		// 数组扩容的总大小void resize(){}
}

注意:
1、为什么拷贝时要使用for循环,而不是直接

memcpy(ptmp, _pstack, sizeof(int)*_size);

使用memcpy仍然是浅拷贝。
2、赋值构造函数时,有一个释放当前对象的内存的操作。对应shared_ptr引l用计数在赋值的时候也会减1(随即会加1)
3、赋值构造函数应该防止s1 = s1这种自赋值的情况。

编程实践

Mystring:
注意:
1、在普通构造函数中,无论如何也要开辟一块内存。保证对象是有一个有效的对象。
2、普通构造函数的输入为const char *str,因为在新版编译器中不让普通的指针指向常量字符串

char *p = "hello world";  // 不能修改*p
现在编译器都不让普通的指针指向常量字符串,应该这么写:
const char *p = "hello world";
#include <bits/stdc++.h>using namespace std;class String
{
public:String(const char *str = nullptr) {if (str != nullptr){m_data = new char[strlen(str) + 1];  // 加上'/0'strcpy(this->m_data, str);}else{m_data = new char[1]; // new char;*m_data = '\0'; // 0}}String(const String &other){m_data = new char[strlen(other.m_data) + 1]; // 深拷贝strcpy(m_data, other.m_data);}~String(void)  // 析构函数{delete[]m_data;m_data = nullptr;}// String& 是为了支持连续的operator=赋值操作String& operator=(const String &other) // 赋值重载函数{if (this == &other){return *this;  // str1}delete[]m_data;    // 析构m_data = new char[strlen(other.m_data) + 1];strcpy(m_data, other.m_data);return *this; // str1}
private:char *m_data; // 用于保存字符串
};
int main()
{// 调用带const char*参数的构造函数String str1;String str2("hello");String str3 = "world";// 调用拷贝构造函数String str4 = str3;String str5(str3);// 调用赋值重载函数/*str1 = str2str1.operator=(str2) => str1str3 = str1*/str3 = str1 = str2;return 0;
}

关于赋值重载函数中返回值为引用的情况:
如果一个方法的返回值是一个引用,那么它返回的是某个对象的引用,而不是对象本身的副本。这意味着通过引用返回的值与原始对象共享同一块内存,对返回值的修改将直接影响原始对象。
返回引用的方法有以下几个作用:

  • 避免对象的复制:通过返回引用而不是副本,可以避免在函数调用中进行大量的复制操作,提高性能。特别是对于大型对象或复杂的数据结构,避免复制可以节省时间和内存。
  • 允许链式操作:返回引用可以使多个方法调用可以连接在一起形成链式操作。这种方法通常用于实现流畅的、易读的代码,比如在输入/输出流中使用<<和>>运算符。
  • 允许对返回值进行修改:返回引用允许在函数外部对返回值进行修改。这可以用于实现函数返回某个对象的引用,以便可以直接修改该对象的状态。

需要注意的是,返回引用时需要确保返回的引用在函数调用结束后仍然有效。一般来说,应该返回指向静态、全局、或动态分配的对象的引用,而不是指向局部对象的引用,以避免出现悬垂引用(dangling references)的问题。

完整的Mystring重写见:参考链接

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

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

相关文章

深入学习 Redis - 深挖经典数据类型之 string

目录 前言 一、string 类型 1.1、操作命令 set / get &#xff08;设置 / 获取&#xff09; mset / mget&#xff08;批量 > 设置 / 获取&#xff09; setnx / setex / psetex &#xff08;设置时指定不同方式&#xff09; incr / incrby / decr / decrby/ incrbyfloat…

船舶中压配电板应用弧光保护,可解决母排故障短路问题,对于提高船舶电站的安全性、稳定性,降低经济损失具有重要意义。-安科瑞黄安南

摘要&#xff1a;船舶中压配电板弧光故障导致的设备损坏和停电事故&#xff0c;不仅会造成较大的经济损失&#xff0c;而且严重影响船舶电站的安全稳定运行&#xff0c;威胁船舶电站操作人员的安全。弧光保护是基于电力系统开关柜发生弧光故障时而设计的一套母线保护系统&#…

【布局优化】基于遗传算法的车间布局优化 车间设施布局优化【Matlab代码#50】

文章目录 【获取资源请见文章第5节&#xff1a;资源获取】1. 车间布局优化2. 基于GA的布局优化模型3. 部分代码展示4. 仿真结果展示5. 资源获取 【获取资源请见文章第5节&#xff1a;资源获取】 1. 车间布局优化 车间设施布置的规划一直是工业工程领域不断研究和探索的内容&am…

JavaWeb(5)——HTML、CSS、JS 快速入门

一、JavaScript 对象 二、JavaScript BOM对象 和 DOM对象 关于BOM主要对 Window 和 location 进行说明&#xff1a; 三、JavaScript 事件监听 事件绑定 常见事件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…

谷歌Bard:ChatGPT之外的第三选择

2023年年初&#xff0c;为了对应ChatGPT方面的压力&#xff0c;谷歌Bard仓促上线&#xff0c;此后便进入了低调前行。目前为止已经迭代了9个版本&#xff0c;也就是在近期的版本更新中支持了中文&#xff08;简体/繁体&#xff09;语言&#xff0c;对国内用户可以说又友好了一步…

物理层——数据通信基础知识

1.典型的数据通信模型 2.数据通信的相关术语 2.1 三种通讯方式 2.2 数据传输方式 2.3 常用编码方式&#xff08;数字信号&#xff09; 曼彻斯特编码 将一个码元分成两个相等的间隔&#xff1b; 前一个间隔为 低电平 &#xff0c;后一个间隔为 高电平 表示码元1&#xff1b; 码…

el-dialog 添加loading;avue-form 表单插槽

效果: 第一步&#xff1a;custom-class"publishDialog" 新起一个类名 <el-dialog title"发布配置" custom-class"publishDialog" :visible.sync"publishDialogVisible" width"800px" :append-to-body"true":b…

babel兼容低版本游览器

文章目录 1. webpack项目的搭建2. babel 命令行使用3. babel的预设与编译器流程4. babel项目中配置4.1 babel-loader与插件的使用4.2 babel-preset使用 5. 游览器兼容性使用5.1 browserslist工具与编写规则5.2 browserslist配置5.3 优化babel的配置文件 6. polyfill6.1 useBuil…

Flutter——最详细(NavigationRail)使用教程

NavigationRail 简介 一个 Material Design 小部件&#xff0c;旨在显示在应用程序的左侧或右侧&#xff0c;以便在少量视图&#xff08;通常在三到五个视图之间&#xff09;之间导航。 使用场景&#xff1a; 通过Row属性&#xff0c;左侧或右侧菜单栏按钮 属性作用onDestinati…

Halcon机器视觉-15种常用缺陷检测实例

一、Halcon 15种常用缺陷检测实例分享 缺陷检测是一种通过计算机视觉技术来检测产品制造过程中的缺陷的方法。该技术可以检测出产品表面的缺陷&#xff0c;如裂纹、凹陷、划痕、气泡等&#xff0c;并且可以实时监测和诊断制造过程中的问题。在制造业中&#xff0c;机器视觉缺陷…

GRE实验

题目参考&#xff1a; 实验步骤&#xff1a; 第一步&#xff1a;地址规划拓扑设计&#xff0c;配置IP地址 R1配置&#xff1a; <Huawei>system-view [Huawei]sy R1 [R1]int g 0/0/1 [R1-GigabitEthernet0/0/1]ip address 192.168.1.1 24 [R1-GigabitEthernet0/0/1]in…

智能电表数据采集器

智能电表数据采集器是一种用于采集智能电表数据的设备&#xff0c;它可以将智能电表的数据传输到远程服务器上&#xff0c;以便进行数据分析和监控。智能电表数据采集器的主要功能是采集智能电表的实时数据&#xff0c;并将其发送到远程服务器上&#xff0c;从而实现对智能电表…

【windows测试通过】关于Godot导入外部音频文件的问题

file.open(filepath, file.READ) var buffer file.get_buffer(file.get_len()) #put data into audiostreamsample var stream AudioStreamSample.new() stream.data buffer 代码给出&#xff0c;还没有测试过。(godot3.2测试未通过&#xff09; 在运行时轻松加载外部音频…

业务安全分析第19期 | 今年暑假,博物馆的门票为什么抢不到?

目录 “黄牛”&#xff1a;加价代预约、加价售票、兜售野导游套餐 “黄牛”倒票带来的危害 “黄牛”为什么能够抢到票 博物馆与“黄牛”的门票攻防 “黄牛”使用的作弊软件有什么特征 技术上防范“黄牛”的作弊软件抢票 遏制“黄牛”倒票给博物馆带来的收益 随着暑期参观…

[nlp] GPT

一、联合训练任务 1.1 NTP(Next Token Prediction) gpt预训练的一个目标函数有两个,第一个是基础的下一个词预测任务,选择一个K窗口,将窗口中的K个词的embedding作为条件去预测下一个词。 1.2 TC(Text Classification) 第二个是一个分类任务,一段话给一个标签,然后去预…

离线数据仓库

一、数据仓库 1.数据仓库的概念 1)数据仓库的特点: 面向主题的:对数据进行整合、分析和归类的抽象集成的:将不同数据源的数据(业务数据、外部系统数据、埋点日志)经过统一编码、规范命名、字段类型转换等操作,整合到仓库相对稳定的:根据业务场景实时更新、一般会被长…

VIM文本如何复制到系统剪切板?

今天从vim上用鼠标复制代码&#xff0c;发现把VIM当中的行号也复制进去了&#xff0c;就很麻烦&#xff0c;于是简单研究了下&#xff0c;如果vim支持clipboard的话就比较好办&#xff0c;具体支持与否&#xff0c;使用命令查看&#xff1a; vim --version | grep "clipb…

startqueue(模拟实现及底层原理)

目录 容器适配器 STL标准库中stack和queue的底层结构 ​deque deque的原理 deque的缺陷 为什么选择deque作为stack和queue的底层默认容器 stack stack的介绍 stack的函数 stack的模拟实现 queue queue的介绍 queue的函数 queue的模拟实现 priority_queue prior…

Android中线程池

一、线程池的优点 说到线程池的优点就要先说一下不用线程池的坏处 在早些年开发都是直接new Thread()直接创建线程&#xff0c;倘若有N个异步就要创建N个线程&#xff0c;这会导致线程的频繁创建和销毁线程不可控&#xff0c;每个线程都各自执行&#xff0c;内存资源竞争激烈&…

js小写金额转大写 自动转换

// 小写转为大写convertCurrency(money) {var cnNums [零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖]var cnIntRadice [, 拾, 佰, 仟]var cnIntUnits [, 万, 亿, 兆]var cnDecUnits [角, 分, 毫, 厘]// var cnInteger 整var cnIntLast 元var maxNum 999999999999999.9999var…