【深度解析C++之运算符重载】

系列文章目录

🌈座右铭🌈:人的一生这么长、你凭什么用短短的几年去衡量自己的一生!

💕个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C++,自顶向下看Java-CSDN博客

❤️相关文章❤️:【深度解析C++之this指针】-CSDN博客文章浏览阅读795次,点赞21次,收藏22次。一、为什么需要this指针this指针是C++当中用于指向当前对象的指针,它是成员函数内的一个隐式参数,指向调用该成员函数的对象的内存地址(this指针存放的内容就是对象的内存地址),this指针的主要用途是在成员函数内部访问对象的成员变量和调用其他的成员函数。在类的成员函数当中,如果存在与类的成员变量同名的局部变量或者函数参数,编译器可能无法区分它们,这个时候我们就需要使用this指针可以明确地指出成员变量属于当前对象。https://blog.csdn.net/weixin_59658448/article/details/135136967


目录

系列文章目录

前言

一、运算符重载是什么?

1、基本概念

2、为什么要引入运算符重载

        1、自然语法:

        2、代码简洁性:

        3、类的抽象性:

        4、标准库兼容

 二、运算符重载的特性

1.参数类型:const T&

        1、效率提升

        2、避免修改输入参数

2.返回值类型:T&

        1、效率提升:

        2、支持连续赋值:

3、防御性编程:

         1、为自身赋值

        2、为自身赋值的后果

        1. 资源泄漏: 

        2. 不一致的状态:

        3. 程序崩溃或不稳定:

 4、返回*this:复合连续赋值的含义

        1、*this的作用:

        2、*this与引用返回

三、前置++与后置++

1、前置++

        1、返回类型为引用:

        2、先递增后返回:

        3、推荐使用前置递增:

2、后置++

        1、回类型为值:

        2、使用参数区分前后置:

        3、先返回后递增:

 总结


前言

        这篇文章主要为大家讲解C++当中的运算符重载的问题,学习这篇文章需要对C++的this指针足够的了解,链接我已经为大家放到了文章的开头如果又需要的话请查收。我将全方位地为大家讲解运算符重载,一次性解决各位初学者的所有疑问。


一、运算符重载是什么?

1、基本概念

        当我们谈到运算符重载时,我们实际上是在讨论如何重新定义 C++ 中的某个运算符,使其适用于用户自定义的类或数据类型。运算符重载通过定义特殊的成员函数来实现,这些成员函数以 operator 关键字开头,后接需要重载的运算符符号。

        下面是一个运算符重载函数的通用格式:

返回值类型 operator运算符(参数列表) {// 运算符的实现代码
}

        接下来我来用代码为大家演示一下什么叫做运算符重载:

class MyClass {
private:double value;
public:MyClass(double value) :value(value) {}MyClass operator + (const MyClass& other)const {return MyClass(value + other.value);}MyClass operator - (const MyClass& other)const {return MyClass(value - other.value);}MyClass operator * (const MyClass& other)const {return MyClass(value * other.value);}MyClass operator / (const MyClass& other)const {if (other.value != 0) {return MyClass(value / other.value);}else {cerr << "Error: Division by zero:" << endl;return MyClass(0);}}MyClass& operator++(){++this->value;return *this;}MyClass& operator++(int) {MyClass tmp(*this);++this->value;return tmp;}double getValue() {return this->value;}
};
int main() {MyClass obj1(2.0);MyClass obj2(4.0);MyClass obj3 = obj1 + obj2;MyClass obj4 = ++obj1;cout << obj3.getValue() << endl;cout << obj4.getValue() << endl;return 0;
}

        再上面的代码当中我们重载了加法运算符、减法运算符等等,通过这样的方式我们定义了让两个对象当中的值相加的过程,运算符重载是C++当中一种灵活的方式,让用户自定义类型的对象能够使用类似于内置类型的语法进行操作。

2、为什么要引入运算符重载

        1、自然语法:

        运算符重载使得用户自定义的类型能够使用类似于内置类型的语法进行操作。例如,通过重载加法运算符,你可以使用object1 + object2的形式进行对象相加,这样的语法更接近我们日常的数学表达方式,使代码更易读。

        2、代码简洁性:

        运算符重载可以简化代码,使其更紧凑而易于理解。通过自定义运算符的行为,你可以隐藏底层实现细节,使代码更具表达力。

        3、类的抽象性:

        运算符重载有助于创建更抽象的类,使其更符合问题领域的模型。例如,通过重载比较运算符,你可以定义自定义类对象之间的比较规则,使得类在各种情境下都能够直观地比较。

        4、标准库兼容

        运算符重载使得用户自定义类型能够与标准库当中的算法和容器协同工作,例如如果你的类支持小于运算符的重载、那么对象就可以用于STL当中的排序算法当中,这就是标准库兼容,虽然运算符重载有着很多的优势,但是如果过度使用也会导致代码的混乱和不容易理解,因此在进行运算符重载的时候建议谨慎选择。


 二、运算符重载的特性

1.参数类型:const T&

        参数类型为 const T& 表示传递的参数是一个对常量类型 T 的引用。这有两个主要好处

        1、效率提升

        避免拷贝构造函数调用:通过使用引用而不是直接传递对象,可以避免不必要的拷贝构造函数的调用。如果使用非引用的方式传递参数,会导致传递的对象被复制一份,调用拷贝构造函数,增加了额外的开销,特别是对于大型对象或者自定义类型来说,这样的开销是不必要的。通过传递引用,可以直接操作原始对象,提高了传参的效率。

        2、避免修改输入参数

        使用 const 修饰:参数类型中的 `const` 关键字确保在函数内部不能修改传递的对象。这是通过将对象声明为常量引用来实现的。如果在函数内部尝试修改这个引用所引用的对象,编译器会报错。这样的设计有助于保护传递的对象不被意外地修改,提高了代码的健壮性和可维护性。

        

void processData(const std::string& input) {// 不能修改 input,只能读取其中的数据// ...
}

        `processData` 函数接受一个 `std::string` 类型的常量引用作为参数。这确保了在函数内部不能修改传递的字符串,而且通过引用的方式传递参数,也避免了不必要的字符串拷贝。

2.返回值类型:T&

        返回类型为 T& 表示返回的是对类型 T 的引用。这也有两个主要优势:

        1、效率提升:

        避免返回时的拷贝:返回引用而不是对象本身避免了在函数返回时发生不必要的拷贝构造函数调用。如果函数返回对象本身而不是引用,那么在返回时需要创建一个副本,调用拷贝构造函数,这可能会导致性能开销。通过返回引用,可以直接返回原始对象,提高了效率。

        2、支持连续赋值:

        允许链式赋值操作:返回引用允许进行连续赋值操作,例如 `a = b = c`。这是因为返回的是对象的引用,而不是对象本身,所以可以在赋值操作中继续引用相同的对象。这种语法糖提高了代码的简洁性和可读性。

class MyClass {
private:int value;
public:MyClass(int value) :value(value) {}MyClass& setValue(int num) {this->value += num;return *this;}int getValue() {return this->value;}
};
int main() {MyClass obj1(10);obj1.setValue(2).setValue(5).setValue(7);cout << obj1.getValue() << endl;return 0;
}

        程序的运行结果如下:因为当我们返回一个对象的引用的时候,返回的是一个对象的别名我们就可以继续使用这个对象连续的进行同样的操作,这就叫做对象的链式调用,如果有小伙伴关于this指针这部分的内容有不理解的话,可以看我之前写过的一篇this指针的专题文章,那里面有对于this指针的详细介绍。

3、防御性编程:

         1、为自身赋值

        在赋值操作符重载中,检测自己给自己赋值是为了防止资源泄漏或不一致的状态。通常,你会看到类似以下的代码:

MyClass& MyClass::operator=(const MyClass& other) {// 检测是否自己给自己赋值if (this != &other) {// 执行赋值操作// ...}return *this;
}

        在赋值操作符重载中检测自己给自己赋值是一种防御性编程的做法,目的是避免可能导致资源泄漏或不一致状态的情况发生。如果大家对于这段话不理解的话,我用代码来解释,以下是一个常见的检测自赋值的代码模式:

#include <iostream>class Example {
public:int* data;size_t size;// 构造函数Example(size_t s) : size(s) {data = new int[size];}// 析构函数~Example() {delete[] data;}// 赋值操作符重载Example& operator=(const Example& other) {// 检测自赋值if (this != &other) {// 进行赋值操作delete[] data;  // 释放原有资源size = other.size;data = new int[size];std::copy(other.data, other.data + size, data);  // 复制数据}return *this;}
};int main() {Example obj1(3);Example obj2(5);obj1 = obj2;  // 赋值操作return 0;
}

        大家尤其注意一下这段代码:

 // 赋值操作符重载Example& operator=(const Example& other) {// 检测自赋值if (this != &other) {// 进行赋值操作delete[] data;  // 释放原有资源size = other.size;data = new int[size];std::copy(other.data, other.data + size, data);  // 复制数据}return *this;}

        大家可以想象一下如果我在主函数当中进行了这样的操作:

int main() {MyClass obj1(20);obj1 = obj1;return 0;
}

        如果我进行了这样的操作,而且这个对象单中含有data这样的指针成员,我不进行任何的判断就执行了这样的代码:

delete[] data;  // 释放原有资源size = other.size;data = new int[size];std::copy(other.data, other.data + size, data);  // 复制数据

        大家可以想象一下会有什么样的后果,一个对象因为自己给自己赋值然后不分青红皂白地就把自己的数据给删除了,这样会导致非常严重的后果,这个对象的数据会丢失,资源造成泄漏,所以我们在进行运算符重载的时候一定要判断一下,不能够直接删除数据。

        2、为自身赋值的后果

        在上述例子中,`operator=` 被重载以处理 `Example` 类型对象的赋值操作。在赋值之前,首先检测了是否是自赋值,即 `this != &other`。如果是自赋值,就不进行释放和拷贝的操作,以避免释放正在使用的资源,并保持对象的一致性。 这种检测自赋值的做法在处理动态分配的资源(比如堆内存)时尤为重要。如果不进行自赋值检测,可能导致在释放原有资源之前就将其覆盖,从而导致资源泄漏或者出现不一致的状态。通过检测自赋值,可以确保赋值操作的安全性和一致性。 如果在赋值操作符重载中不进行自赋值检测,可能会导致以下危害:

        1. 资源泄漏: 

        假设你有一个包含动态分配内存的类,如果没有检测自赋值并在赋值前释放资源,那么在自赋值的情况下就会导致原有的资源丢失,无法释放,从而发生内存泄漏。

        2. 不一致的状态:

        如果在进行自赋值时不检测,可能会导致对象的状态处于不一致的状态。例如,在拷贝数据之前删除原有数据,这样会导致拷贝时访问无效的内存,导致未定义行为。

        3. 程序崩溃或不稳定:

        不进行自赋值检测可能导致程序崩溃或不稳定的行为。在自赋值情况下,如果不小心释放了正在使用的资源,可能导致悬挂指针或无效内存访问,最终导致程序崩溃。

#include <iostream>class Example {
public:int* data;size_t size;Example(size_t s) : size(s) {data = new int[size];}~Example() {delete[] data;}Example& operator=(const Example& other) {// 没有自赋值检测// 可能导致资源泄漏和不一致的状态delete[] data;  // 错误:没有检测自赋值size = other.size;data = new int[size];std::copy(other.data, other.data + size, data);return *this;}
};int main() {Example obj(3);obj = obj;  // 自赋值return 0;
}

        代码我为大家放到了这里,有兴趣的话可以自己去验证一下会发生什么。编译虽然不会报错但是程序已经出现了巨大的安全问题。

 4、返回*this:复合连续赋值的含义

        1、*this的作用:

        return *this 的目的是支持连续赋值。在连续赋值中,每个赋值表达式的返回值都是被赋值的对象的引用。例如,a = b = c,首先 b = c 返回 b 的引用,然后 a = b 返回 a 的引用。这种返回自身引用的方式允许多个赋值操作可以串联在一起。

        我不知道大家是否还记得我刚刚在对象的链式调用当中提过这个知识点,代码如下,在实现链式调用的过程当中一方面返回值是引用而且return后面的语句就是*this。

class MyClass {
private:int value;
public:MyClass(int value) :value(value) {}MyClass& setValue(int num) {this->value += num;return *this;}int getValue() {return this->value;}
};
int main() {MyClass obj1(10);obj1.setValue(2).setValue(5).setValue(7);cout << obj1.getValue() << endl;return 0;
}

        this指针指向的是这个对象本身,可以说是对象在内存当中的地址,那么*this就是对这个对象进行解引用,返回的也就是这个对象本身。和链式调用相互配合。

        2、*this与引用返回

        各位小伙伴这部分的内容非常重要,也困扰了我很长的时间,今天我一次性给大家讲清楚。

  1. 新对象 vs. 原对象:如果返回新创建的对象而不是引用,那么每次调用函数时都会生成一个新的对象。这意味着每次操作都会创建新的对象,而不是在原对象上进行修改。这样的设计可能更适合不希望改变原始对象状态的情况。
  2. 复制成本:返回对象可能涉及到复制构造函数的调用,这可能导致一些额外的开销。如果你的对象比较大或者复制构造函数比较昂贵,这种设计可能会影响性能。
  3. 不支持链式调用:如果不返回引用,就不能支持链式调用,无法在一行代码中连续调用多个该类的成员函数。
     

        如果文字大家还是不能够明白的话请看这样的一段代码:
 

class MyClass {
private:int value;
public:MyClass(int value) :value(value) {}MyClass setValue(int num) {this->value += num;return *this;}int getValue() {return this->value;}
};
int main() {MyClass obj(5);obj.setValue(10);cout << obj.getValue() << endl;obj.setValue(1);cout << obj.getValue() << endl;obj.setValue(5).setValue(7).setValue(5);cout << obj.getValue() << endl;return 0;
}

        代码的运行结果如下:当我不适用引用返回的时候并且这个时候还调用了对象的链式调用是没有用的,因为*this是对象本身,如果不返回引用的话返回的是对象本身,每一次调用函数返回的都是一个新的对象,无法在原来的对象上进行操作,无法实现函数的连续调用也就是对象的链式调用。

        可能到了这里小伙伴会有一个疑问,为什么*this就是对象本身的意思,可是使用引用返回就能够返回对象的引用呢?this指针指向对象,对这个指针解引用应该就是对象本身啊,难道就因为返回值的类型是引用*this就能返回引用吗?

        答案很简单因为编译器做了优化,给*this对象本身临时绑定了一个引用,所以链式调用的时候不管我们执行多少次返回的都是同一个对象的引用,所以可以利用链式调用对同一个对象进行多次重复的操作。


三、前置++与后置++

1、前置++

        重载前置和后置递增运算符 ++ 是面向对象编程中的一项常见任务。这两者之间有一些细微的差异,前置递增运算符也就是 ++i:

T& operator++();  // 返回引用

        1、返回类型为引用:

        前置递增运算符返回引用,允许对同一对象进行连续递增操作,因为返回的是原始对象的引用。前置++是对对象本身的值进行了修改所以返回的也必须是对象本身。

        2、先递增后返回:

        首先对对象进行递增操作,然后返回递增后的对象的引用。

        3、推荐使用前置递增:

        在性能上,前置递增通常比后置递增更高效,因为前置递增直接对原始对象进行操作,而后置递增需要创建一个副本,增加了额外的开销。

2、后置++

        后置++与前置++的区别就是在参数列表当中写一个int,这个int没有任何的意义,就是为了区分前后的。

T operator++(int);  // 参数int用于区分前置和后置递增

        1、回类型为值:

        后置递增运算符返回一个值,而不是引用。这是因为后置递增要返回递增前的原始值,而不是递增后的对象。

        2、使用参数区分前后置:

        后置递增运算符的参数是一个(通常是未使用的)整数,用于在函数签名上区分前置和后置版本。

        3、先返回后递增:

        首先返回递增前的原始值,然后再对对象进行递增操作。

#include <iostream>class Counter {
private:int count;public:Counter() : count(0) {}// 前置递增运算符Counter& operator++() {++count;return *this;}// 后置递增运算符Counter operator++(int) {Counter temp(*this);  // 保存递增前的值++count;  // 对对象进行递增return temp;  // 返回递增前的值}int getCount() const {return count;}
};int main() {Counter c1;std::cout << "Original Count: " << c1.getCount() << std::endl;// 前置递增++c1;std::cout << "After Pre-increment: " << c1.getCount() << std::endl;// 后置递增Counter c2 = c1++;std::cout << "After Post-increment: " << c2.getCount() << std::endl;std::cout << "Final Count: " << c1.getCount() << std::endl;return 0;
}

        这部分内容简单容易理解,写一段代码为大家演示,这部分内容重点要理解为什么前置++需要引用返回而后置++不需要引用返回,因为前置++是先自增再返回所以这个时候对象本身已经发生了变化,而后置++不同需要先返回自身的值然后再进行自增操作,所以需要引入临时变量,一般我们推荐使用前置++,他的效率更高一些。

        拷贝构造函数当中还有一个很重要的内容就是const成员函数,这个部分我的下一篇文章会为大家详细介绍,const成员不是这篇文章的重点。 


 总结

        这篇文章就为大家介绍到这里,希望我的文章能够帮助到各位小伙伴,今天是2023年的最后一天,这一年发生了很多令我难以忘怀的事情,2023教会了我很多的事情,我的每一份耕耘终于有了让我满意的收获,我现在正满心期待地迎接2024的到来,就用这篇文章致敬2023努力的自己吧!也祝我的每一位粉丝小伙伴新的一年能够诸事顺遂,所得皆所愿,感谢各位的陪伴!😊

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

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

相关文章

OpenGauss 之索引查找和匹配

一. 前言 本文主要通过走读OpenGuass的代码&#xff0c;来了解查询的时候OpenGuass是如何查找表的索引信息以及根据谓词条件过滤掉无用的索引信息的。 二. 索引路径匹配流程 1. 首先OpenGuass在build_simple_rel的时候&#xff0c;首先将一个表以及与他相关的索引都加到rel-&g…

DSL查询语法和RestClient查询文档

目录 DSL查询语法 DLS Query的分类 DSL Query基本语法 全文检索查询 精准查询 地理查询 复合查询 Function Score Query 复合查询 Boolean Query 搜索结果处理 排序 分页 分页 深度分页问题 深度分也解决方案 高亮 RestClient查询文档 快速入门 全文检索查…

MK米客方德品牌 SD NAND在对讲机领域的引领作用

SD NAND在对讲机上的应用 SD NAND在对讲机上广泛应用&#xff0c;为其提供了高效可靠的存储解决方案。 这种存储技术不仅能容纳大量语音和数据文件&#xff0c;而且具有高速读取的特点&#xff0c;保障了实时通信的质量。SD NAND还注重安全性&#xff0c;通过数据加密和访问控…

解锁React魔法门:高效项目开发工作流揭秘

你好&#xff0c;我是坚持分享干货的 EarlGrey&#xff0c;翻译出版过《Python编程无师自通》、《Python并行计算手册》等技术书籍。 如果我的分享对你有帮助&#xff0c;请关注我&#xff0c;一起向上进击。 创作不易&#xff0c;希望大家给一点鼓励&#xff0c;把公众号设置为…

OSCHINA Gitee 联合呈现,《2023 中国开源开发者报告》正式发布,总结分非常帮,可以免费看的报告!

《2023 中国开源开发者报告》 详细地址&#xff1a; https://talk.gitee.com/report/china-open-source-2023-annual-report.pdf 不需要收费下载&#xff01;&#xff01; 其中大模型的部分总结的非常棒 gietee 也支持 AI 模型托管了 如何在 Gitee 上托管 AI 模型 https://…

【java爬虫】使用element-plus进行个股详细数据分页展示

前言 前面的文章我们讲述了获取详细个股数据的方法&#xff0c;并且使用echarts对个股的价格走势图进行了展示&#xff0c;本文将编写一个页面&#xff0c;对个股详细数据进行展示。别问涉及到了element-plus中分页的写法&#xff0c;对于这部分知识将会做重点讲解。 首先看一…

Autosar MCAL-RH850P1HC Dio配置

文章目录 DioDioGeneralDioCriticalSectionProtectionDioDevErrorDetectDioDeviceNameDioFlipChannelApiDioMaskedWritePortApiDioUseWriteVerifyErrorInterfaceDioVersionCheckExternalModulesDioVersionInfoApiDioWriteVerifyDioWriteVerifyErrorInterface DioPortP0-P9DioPo…

管道进行进程间通信(上)

管道进行进程间通信 在posix和system V标准还没有出现的时候&#xff0c;进程间是如何进行通信的呢&#xff1f;这就要借助于我们今天学习的这个东西了。在进程间通信的标准没有出现之前&#xff0c;在os中就已经存在了文件了。而管道就是基于文件的一种进行进程间通信的方式。…

WorkPlus为企业打造私有化部署IM解决方案

在移动数字化时代&#xff0c;企业面临着如何全面掌控业务和生态的挑战。企业微信、钉钉、飞书、Teams等应用虽然提供了部分解决方案&#xff0c;但无法满足企业的私有化部署需求。此时&#xff0c;WorkPlus作为安全专属的移动数字化平台&#xff0c;被誉为移动应用的“航空母舰…

独热编码的两种实现形式

独热编码的两种实现形式&#xff1a; ​ OneHotEncoder和DictVectorizer是两种常用的特征向量化方法&#xff0c;用于将分类特征转换为数值特征。但还是有一定的区别不管是再输入格式还是在输出类型上都有一些不同。 区别&#xff1a; 输入格式要求&#xff1a; OneHotEncod…

小梅哥Xilinx FPGA学习笔记18——专用时钟电路 PLL与时钟向导 IP

目录 一&#xff1a;IP核简介&#xff08;具体可参考野火FPGA文档&#xff09; 二&#xff1a; 章节导读 三&#xff1a;PLL电路原理 3.1 PLL基本实现框图 3.2 PLL倍频实现 3.3 PLL分频实现 四: 基于 PLL 的多时钟 LED 驱动设计 4.1 配置 Clocking Wizard 核 4.2 led …

NXP实战笔记(二):S32K3xx基于RTD-SDK在S32DS上配置PIT与STM中断并反转IO

目录 1、PIT 1.1、PIT概述 1.2、PIT的配置 1.3、Dio配置 1.4、中断配置 1.5、测试代码 1.6、测试结果 2、STM 2.1、STM概述 2.2、STM的配置 2.3、测试代码 2.4、测试结果 1、PIT 1.1、PIT概述 PIT是一组定时器&#xff0c;可用于引发中断和触发器&#xff0c;包括一…

PyQt5-控件之QDialog(UI-业务分离搭建自定义xDialog)

1.继承QtWidgets.QWidget自定义对话框 继承于QtWidgets.QWidget自定义一个对话框类&#xff1a;SelectingDlg class SelectingDlg(QtWidgets.QWidget): def __init__(self): super(SelectingDlg, self).__init__() self.initUI() def initUI(self):s…

数据结构和算法-B+树(性质 查找)

文章目录 B树叶子节点B树的查找第一种查找方式第二种查找方式 小结 B树 B树节点的关键个数1B树该节点的子树个数 B树节点的关键字个数和节点的子树个数一样 叶子节点包含全部关键字&#xff0c;并且都相互链接了 叶子节点 根节点也能是叶子节点 B树的查找 第一种查找方式…

HTTP分数排行榜

HTTP分数排行榜 介绍一、创建数据库二、创建PHP脚本三、上传下载分数四、测试 介绍 Unity中向服务器发送用户名和得分&#xff0c;并存入数据库&#xff0c;再讲数据库中的得分按照降序的方式下载到Unity中。 一、创建数据库 首先&#xff0c;我们要在MySQL数据库中建立一个…

Adobe ColdFusion 文件读取漏洞(CVE-2010-2861)

漏洞原理 Adobe ColdFusion是美国Adobe公司的一款动态Web服务器产品&#xff0c;其运行的CFML&#xff08;ColdFusion Markup Language&#xff09;是针对Web应用的一种程序设计语言。由于AJP协议设计存在缺陷导致内部相关的属性可控&#xff0c;攻击者可以构造属性值&#xff…

.NET Core中灵活使用反射

前言 前段时间有朋友问道一个这样的问题&#xff0c;.NET Core中如何通过Attribute的元数据信息来调用标记的对应方法。我第一时间想到的就是通过C#反射获取带有Custom Attribute标记的类&#xff0c;然后通过依赖注入&#xff08;DI&#xff09;的方式获取对应服务的方法并通…

中小微医院机构云服务(云HIS)平台源码

云HIS&#xff08;Cloud-Based Healthcare Information System&#xff09;重新定义了HIS&#xff0c;目标是为中小型医疗卫生机构提供优质经济的医疗卫生信息化产品及服务&#xff1b;是以健康档案为主线、以电子病历为核心、以云计算技术为基础的医疗卫生系统。云HIS作为基于…

王道考研计算机组成原理——存储系统

存储系统的基础知识 微信打开的时候会有一个人站在地球上&#xff0c;这个过程就是把程序从辅存转移到主存&#xff0c;数据只有调入主存当中才可以被CPU访问 cache&#xff1a;主存速度还是慢&#xff0c;为了进一步缓解CPU和主存之间的速度矛盾 在微信打视频聊天的时候&am…

Git 常用命令(从远程gitee/GitCode/GitHub下载项目到本地仓库)

​分布式项目控制管理gitGit 分布式版本控制系统(序章1)windows和linux操作Git(序章2) git在windows和ubuntu操作命令无异。本次举例平台&#xff1a;ubuntu18.04 查看是否安装和查看版本号 git --version # 仓库 # 在当前目录新建一个Git代码库$ git init​# 新建一个目录…