【C++】类和对象—(下) 收官之战

【C++】类和对象—(下) 收官之战

前言:上一篇文章我们向大家介绍了类和对象的核心六个成员函数中的4个,其余两个以及初始化列表,static成员,内部类,匿名对象等会在本篇文章介绍!

在这里插入图片描述
✨ 坚持用清晰易懂的图解+代码语言, 让每个知识点都简单直观!
🚀 个人主页MSTcheng · ZEEKLOG
🌱 代码仓库MSTcheng · Gitee
📌 专栏系列 :📖 《C语言》🧩 《数据结构》💡 《C++由浅入深》💬 座右铭 :“路虽远行则将至,事虽难做则必成!”

文章目录

一,运算符重载

1.1什么是运算符重载?

类比我们之前学过的函数重载,函数重载的特点就是函数名相同参数不同。那么运算符重载也一样,运算符重载就是将普通的运算符重载成为一个函数,在使用的时候就去调用对应的函数即可。

1.2 为什么要创造运算符重载?

使问题简单化:首先无论是C还是C++的内置类型都支持运算符操作,但是自定义类型是不支持的。比如日期类,日期加日期,日期减日期,这是没办法使用普通的运算符去实现的。因此C++支持这种重载能够让复杂的自定义类型也能够使用简单的运算符符号,本质就是让复杂的问题简单化。扩展语言的表达能力:通过重载<<流提取>>流插入
可以输入输出自定义类型的内容,以及重载下标运算符[]可以让类模拟数组的行为等等。

简单的了解了运算符重载后我们就来介绍一下赋值运算符重载。

二,赋值运算符重载

2.1赋值运算符重载的构成

1.运算符重载的构成为:operator+运算符(参数),所以赋值运算符重载就是
operator =() 其余的运算符在重载的时候也类似。下面以日期类为例:
#include<iostream>usingnamespace std;classDate{public:Date(int year =1,int month =1,int day =1){ cout <<"Date(int year = 1, int month = 1, int day = 1)"<< endl; _year = year; _month = month; _day = day;}//为了避免我们在重载==等号 这个运算符会误将==写成=赋值 所以我们加上const修饰 d就不能改变了那么写成赋值就会报错 Date&operator=(const Date& d){// 要检查⾃⼰给⾃⼰赋值的情况if(this!=&d){ _year = d._year; _month = d._month; _day = d._day;}// d1 = d2表达式的返回对象应该为d1,也就是 * thisreturn*this;}private:int _year;int _month;int _day;};intmain(){ Date d1(2025,4,26);//注意这是拷贝构造 拷贝构造是用一个已经存在的对象去初始化另一个对象 Date d2=d1; Date d3(2025,5,26); Date d4(2025,6,26);//这里是赋值重载 是两个已经存在的对象之间的赋值!!! d1 = d3;//连续赋值 d1 = d3 = d4;return0;}

代码分析:

在这里插入图片描述
观察上面的代码我们可以知道赋值运算符的特点:有返回值:作为六个默认成员函数之一,它相较于其他无返回的成员函数不同它有返回值,且返回什么根据自己的需求定义。比如比较大小的运算符重载返回的就是布尔值。
2.在没有显示写此函数时,编译器也会自动生成。生成的函数跟拷贝构造函数类似会对对象进行值的拷贝(浅拷贝),而对于自定义类型则会调用它的赋值重载函数。

注意:.*::sizeof?:. 注意以上5个运算符不能重载。

2.1 >>流插入<<流提取重载


首先来看库里面的的流插入和流提取,它们也是重载得到的,那在重载自定义类的的流插入和流提取就只要注意this指针抢占问题,下面来看代码:
classA{public://定义在类里面 ostream&operator<<(ostream& out,const Date& d){ out << d._year <<"年"<< d._month <<"月"<< d._day <<"日"<< endl;return out;}}//定义在类外面 全局函数 ostream&operator<<(ostream& out,const Date& d){ out << d._year <<"年"<< d._month <<"月"<< d._day <<"日"<< endl;return out;}
在这里插入图片描述
重载<<和>>时,需要重载为全局函数。 因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了对象<<cout,不符合使⽤习惯和可读性。 重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。

3.1const成员函数

const成员函数就是被const修饰的成员,const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。const 修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this
在这里插入图片描述

4.1取地址运算符重载

这两个成员函数用的很少一般编译器自动生成的函数就够用了,当我们不想让别人取到对象的地址时才使用:
classDate{public: Date*operator&(){returnthis;//return nullptr;}const Date*operator&()const{returnthis;//return nullptr;}private:int _year ;int _month ;int _day ;}

三,初始化列表

3.1 再探构造函数

在上一篇文章中我们给大家介绍了构造函数,我们知道构造函数就是执行初始化功能的函数,每一个对象在创建好时都会调用对应的构造去初始化对象内部的成员变量,但当时我们并不知道对象里的成员变量到底是怎么初始化的?成员变量实际上是通过初始化列表来初始化的,下面我们就来认识一下初始化列表。

3.2初始化列表

构成:在构造函数中,初始化列表的使⽤方式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。
classDate{public:Date(int year =1,int month =1,int day =1)//初始化列表:_year(year),_month(month),_day(day){}private:int _year;int _month;int _day;};
以上面的日期类举例,以前我们是在函数内部完成初始化,现在我们将这些成员变量拿出来外面初始化,其中还有很多细节我们画图来解释:
在这里插入图片描述

到这里可能有人要问:使用初始化列表跟以前在函数内部的初始化好像没什么区别,那初始化列表存在的意义是什么呢?

首先我们如果写初始化列表其实编译器也会去走初始化列表将成员变量初始化成0或随机值,只不过我们后面在函数体内部又手动的初始化了所以我们感受不到编译器使用初始化列表。
另外如果在成员函数中加入自定义类型成员变量const修饰的变量引用成员变量还放在函数体内初始化吗?答案是否定的,这几类成员函数必须要使用初始化列表初始化!
classDate{public:Date(int& x,int year =1,int month =1,int day =1):_year(year),_month(month),_day(day),_t(12),_ref(x),_n(1){//括号内部不能初始化 _t _ret _n 必须放到初始化列表}private:int _year=2025;int _month;int _day; Time _t=1;// 没有默认构造int& _ref;// 引⽤constint _n;// const};
在这里插入图片描述
到这里可能也还有人会问:初始化列表这么好用那以后是不是全都用初始化列表就行了呢?答案是否定的,来看看特殊情况:
typedefint STDataType;classStack{public:Stack(int n =4):_a((STDataType*)malloc(sizeof(STDataType)* n)),_top(0),_capacity(n){//想栈这样又资源的类,判断空间是否开辟成功使用初始化列表就不行 就要在函数体内部完成!if(nullptr== _a){perror("malloc申请空间失败");return;}}private: STDataType* _a; size_t _capacity; size_t _top;};
下面再给一张图让大家理清初始化列表的逻辑:
在这里插入图片描述

四,类型转换和explicit关键字

在之前C语言阶段,我们所接触的类型转换就是内置类型之间的转换比如:浮点数转整型,整型和指针之间,以及指针和指针之间的转换。但是C++就支持内置类型与类类型的转换,以及类类型与类类型之间的转换:
explicit:构造函数使用explicit关键字就不支持隐式类型转换了。
classA{public:// 构造函数在使用explicit就不再支持隐式类型转换// explicit A(int a1)A(int a1):_a1(a1){}//explicit A(int a1, int a2)A(int a1,int a2):_a1(a1),_a2(a2){}voidPrint(){ cout << _a1 <<" "<< _a2 << endl;}intGet()const{return _a1 + _a2;}private:int _a1 =1;int _a2 =2;};classB{public:B(const A& a):_b(a.Get()){}private:int _b =0;};intmain(){// 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3// 编译器遇到连续构造+拷⻉构造->优化为直接构造 A aa1 =1; aa1.Print();const A& aa2 =1;//多参数的类型转换需要使用花括号{} A aa3 ={2,2};//类与类之间的类型转换 aa3隐式类型转换为b对象 B b = aa3;const B& rb = aa3;return0;}

五,static成员

⽤static修饰的成员变量,称之为静态成员变量。
用static修饰的成员函数,称为静态成员函数。
要注意:静态成员变量⼀定要在类外进⾏初始化。
classA{public://静态成员函数被static修饰 是没有this指针的staticintGet_a(){//_b=2; //静态成员函数没有this指针 所以不能访问非静态成员_b 但是可以访问静态成员_areturn _a;}private:// 类里面声明staticint _a;int _b;}//类外面初始化 类里面给缺省值是不显式在初始化列表初始化而给的缺省值,而静态成员不属于对象因此不能在类内初始化。int A::_a=0;intmain(){return0;}
静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。
静态成员的访问方式:可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。

六,友元

友元在之前我们就提到过,一个函数想要在类外面访问就要在这个类内部声明成该类的友元,在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。友元有两种一种是友元函数一种是友元类。

先来看友元函数:

classA{public://定义在类里面friend ostream&operator<<(ostream& out,const Date& d);}//定义在类外面 全局函数 ostream&operator<<(ostream& out,const Date& d){ out << d._year <<"年"<< d._month <<"月"<< d._day <<"日"<< endl;return out;}
在类里面声明了友元就可以在类外面访问该类的私有成员,它可以在类的任意位置声明,也仅仅是一种声明,不是函数!一个函数可以同时是多个类的友元,可以在多个类里面声明友元。

再来看看友元类:

classA{public:friendclassBprivate:int _a;}classB{public:voidfunc(){ cout<<_a<<endl;}private:int _b;}
如果一个类想访问另一个类的私有成员,那么就声明为该类的友元。
注意友元是单向的,A是B的友元A可以访问B的私有但是B不能访问A的私有;A是B的友元,B是C的友元但是A不是C的友元。

七,内部类

内部类,顾名思义就是一个类定义在另一个类的内部。

要点:

1、内部类和外部类实际上是两个独立的类它们是完全平行的不存在包含关系。
2、内部类是外部类的友元类,因此内部类可以访问内部类的私有成员,但外部类不行!
3、内部类本质上是一种封装,如果两个类关系紧密且一个类的实现主要用来给另外一个类使用那么就定义成内部类。
classA{public:friendclassBprivate:int _a;}classB{public:voidfunc(){ cout<<_a<<endl;}private:int _b;}

八,匿名对象

1、用类型(实参) 定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。
2、匿名对象生命周期只在当前一行,一般临时定义⼀个对象当前用一下即可,就可以定义匿名对象。
classA{public:A(int a =0){}~A(){}private:int _a;};intmain(){ A aa1;//定义匿名对象不能这样定义,因为编译器无法识别下面的调用是⼀个函数声明,还是对象定义//A aa1();// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数A();A(1); A aa2(2);return0;}
以上就是本篇文章的所有内容了,感谢各位大佬观看,制作不易还望各位大佬点赞支持一下!有什么问题可以加我私信交流!

Read more

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建

AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建 作者:高瑞冬 本文目录 * AI Agent新范式:FastGPT+MCP协议实现工具增强型智能体构建 * 一、MCP协议简介 * 二、创建MCP工具集 * 1. 获取MCP服务地址 * 2. 在FastGPT中创建MCP工具集 * 三、测试MCP工具 * 四、AI模型调用MCP工具 * 1. 调用单个工具 * 2. 调用整个工具集 * 五、私有化部署支持 * 1. 环境准备 * 2. 修改docker-compose.yml文件 * 3. 修改FastGPT配置 * 4. 重启服务 * 六、使用MCP-Proxy集成多个MCP服务 * 1. MCP-Proxy简介 * 2. 安装MCP-Proxy * 3. 配置MCP-Proxy * 4. 将MCP-Proxy与FastGPT集成 * 5. 高级配置

By Ne0inhk
【大模型实战篇】基于Claude MCP协议的智能体落地示例

【大模型实战篇】基于Claude MCP协议的智能体落地示例

1. 背景         之前我们在《MCP(Model Context Protocol) 大模型智能体第一个开源标准协议》一文中,介绍了MCP的概念,虽然了解了其概念、架构、解决的问题,但还缺少具体的示例,来帮助进一步理解整套MCP框架如何落地。         今天我们基于claude的官方例子--获取天气预报【1】,来理解MCP落地的整条链路。 2. MCP示例         该案例是构建一个简单的MCP天气预报服务器,并将其连接到主机,即Claude for Desktop。从基本设置开始,然后逐步发展到更复杂的使用场景。         大模型虽然能力非常强,但其弊端就是内容是过时的,这里的过时不是说内容很旧,只是表达内容具有非实时性。比如没有获取天气预报和严重天气警报的能力。因此我们将使用MCP来解决这一问题。         构建一个服务器,该服务器提供两个工具:获取警报(get-alerts)和获取预报(get-forecast)。然后,将该服务器连接到MCP主机(在本例中为Claude for Desktop)。         首先我们配置下环

By Ne0inhk
基于腾讯云HAI + DeepSeek快速设计自己的个人网页

基于腾讯云HAI + DeepSeek快速设计自己的个人网页

前言:通过结合腾讯云HAI 强大的云端运算能力与DeepSeek先进的 AI技术,本文介绍高效、便捷且低成本的设计一个自己的个人网页。你将了解到如何轻松绕过常见的技术阻碍,在腾讯云HAI平台上快速部署DeepSeek模型,仅需简单几步,就能获取一个包含个人简介、技能特长、项目经历及联系方式等核心板块的响应式网页。 目录 一、DeepSeek模型部署在腾讯云HAI 二、设计个人网页 一、DeepSeek模型部署在腾讯云HAI 把 DeepSeek 模型部署于腾讯云 HAI,用户便能避开官网访问限制,直接依托腾讯云 HAI 的超强算力运行 DeepSeek-R1 等模型。这一举措不仅降低了技术门槛,还缩短了部署时间,削减了成本。尤为关键的是,凭借 HAI 平台灵活且可扩展的特性,用户能够依据自身特定需求定制专属解决方案,进而更出色地适配特定业务场景,满足各类技术要求 。 点击访问腾讯云HAI控制台地址: 算力管理 - 高性能应用服务 - 控制台 腾讯云高性能应用服务HAI已支持DeepSeek-R1模型预装环境和CPU算力,只需简单的几步就能调用DeepSeek - R1

By Ne0inhk
AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

云边有个稻草人-ZEEKLOG博客 目录 引言 一、什么是DeepSeek? 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型训练与优化 4. 自动化推理与部署 5. 行业专用解决方案 三、蓝耘通义万相2.1与DeepSeek的对比分析 3.1 核心区别 3.2 结合使用的优势 四、蓝耘注册流程 五、DeepSeek与蓝耘通义万相2.1的集成应用 5.1 集成应用场景 1. 智能医疗诊断

By Ne0inhk