【C++】—— 类与对象(一)

news2024/12/27 13:18:34

【C++】—— 类与对象(一)

  • 1、类的定义
  • 2、实例化
    • 2.1、实例化的概念
    • 2.2、对象大小
      • 2.2.1、对象的大小包括什么
      • 2.2.2、内存对齐规则
      • 2.2.3、空类的大小
  • 3、 t h i s this this 指针
  • 4、练习
    • 4.1、题一
    • 4.2、题二

1、类的定义

1.1、类定义

1.1.1、类定义格式

  • c l a s s class class 为定义类的关键字, c l a s s class class 后接类的名字(自己定),{ } 为类的主体,注意类定义结束时,后面的 不能省略

  • 类体中的内容为类的成员:类中的变量称为类的成员变量属性,类中的函数称为类的成员函数方法

  
下面我们简单写一个栈类来感受一下

class Stack
{
public:
	//成员函数
	void Init(int n = 4)
	{
		_a = (int*)malloc(sizeof(int) * n);
		if (nullptr == _a)
		{
			perror("malloc fail");
			exit(1);
		}

		_capccity = n;
		_top = 0;
	}

	void Push(int x)
	{
		// ...扩容
		_a[top++] = x;
	}

	void Destroy()
	{
		fail(_a);
		_a = nullptr;
		_capacity = 0;
		_top = 0;
	}

private:
	//成员变量
	int* _a;
	size_t _capacity;
	size_t _top;
};//分号不能省略

  C++中,并没有规定成员函数和成员变量的位置,只要他们在类中就行,把成员变量混在几个函数的中间也是可以的。但一般来讲都是成员函数在上,成员变量在下。
  

1.1.2、成员变量的标识

  • 为了区分成员变量,一般习惯上成员变量会加上一个特殊的标识,如成员变量前或后加上 _ ;或 m ( m e m b e r ) m(member) m(member) 开头;或 m m m_ 开头。这点C++并没有明确规定,具体看公司的要求

  
  在声明栈类的成员变量时,大家可能发现我在变量名前都加上了 “_”,为什么要这么做呢?
  我们来看一个日期类

class Date
{
public:
	void Init(int year, int month, int day)
	{
		year = year;
		month = month;
		day = day;
	}

private:
	int year;
	int month;
	int day;
};

  可以看到,上述日期类的成员变量与 I n i t Init Init 函数中的形参无法区分,所以为了区分成员变量,要在成员变量前加上特殊的标识
  

1.1.3、C++ 中的 s t r u c t struct struct

  • C++ 中 s t r u c t struct struct 也可以定义类,C++ 中兼容了 C语言 中 s t r u c t struct struct 的用法,同时 s t r u c t struct struct 升级成了
  • 明显的变化是: s t r u c t struct struct 中可以定义函数。 s t r u c t struct struct c l a s s class class 定义类只有一点细微的差别(下面会说),但一般情况下我们还是推荐使用 c l a s s class class 定义类

  
  在C语言,我们定义一个链表的节点,往往是这样定义的:

typedef struct ListNodeC
{
	int val;
	struct ListNode* next;
}ListNodeC;

  
在 C++中, s t r u c t struct struct 升级成了

  1. 类可以定义函数
  2. 名称就可以代表类型,不需要 s t r u c t struct struct + 名称

  

// 不再需要typedef,ListNodeCPP就可以代表类型
struct ListNodeCPP
{
	void Init(int x)
	{
		next = nullptr;
		val = x;
	} 
	
	ListNodeCPP* next;
	int val;
};

  当然,C++ 是兼容 C 的,所以上面的那种方式 C++ 也支持
  

1.1.4、C++ 中的内联函数

  • 在类中定义的成员函数默认是 i n l i n e inline inline,而如果进行声明和定义的分离:声明在类中;定义在类外,则不然。

  

1.1.5、总结

  • c l a s s class class 为定义类的关键字 S t a c k Stack Stack 为类的名字{ } 中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性成员变量;类中的函数称为类的方法或者成员函数
      
  • 为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加 _ 或者 m m m 开头,注意 C++ 中这个并不是强制的,只是一些管理,具体看公司要求
      
  • C++ 中 s t r u c t struct struct可以定义类,C++ 兼容 C 中 s t r u c t struct struct 的用法,同时 s t r u c t struct struct 升级成了类,明显的变化是 s t r u c t struct struct 中可以定义函数,一般情况下我们还是推荐使用 class 定义类
      
  • 定义在类里面的成员函数默认为 i n l i n e inline inline

  

1.2、访问限定符

  可能有小伙伴注意到了,前面定义栈类日期类时,出现了 p u b l i c public public p r i v a t e private private 两个关键字,他们有什么用呢?我们一起来看看

  • C++ 一种实现封装的方式,用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
  • p u b l i c public public 修饰的成员类外可以直接被访问 p r o t e c t e d protected protected p r i v a t e private private 修饰的成员类外不能直接被访问。现阶段我们认为 p r o t e c t e d protected protected p r i v a t e private private 是一样的,以后集成章节才能体现出他们的区别.
  • 访问权限作用域从该访问限定符出现的位置开始,直到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 } (收括号)即类结束
  • c l a s s class class 定义成员没有被访问限定符修饰时默认 p r i v a t e private private s t r u c t struct struct 默认 p u b l i c public public 。这也是 c l a s s class class s t r u c t struct struct唯一区别
  • 一般成员变量都会被限制为 p r i v a t e private private/ p r o t e c t e d protected protected,需要给别人使用的成员函数为 p u b l i c public public。当然这只是一般情况,并没有硬性规定

  

在这里插入图片描述

  
举个栗子:

在这里插入图片描述

  当然,一般情况下也没有人会这样写。一般都是公有的放一起,私有的放一起。
  
像这样:

在这里插入图片描述

  
  

1.3、类域

  在C++中,凡是用 { } 括起来的都会形成一个 。类也不例外,类定义了一个新的作用域: 类域,类的所有成员都在类的作用域中。

  不知大家有没有注意到,在前面定义的栈类中,成员函数的命名不再像之前 C语言 写栈时那样要加上栈的标识,如: void STDestroy()。之前 C语言 这样写是因为结构体和函数是分离的,栈叫 D e s t r o y Destroy Destroy ,队列也叫 D e s t r o y Destroy Destroy 就有可能搞混,且同一个域中也不允许出现同名的变量或函数。
  现在他们是栈类的成员函数,在类域之中,即使后面定义的一个队列域有同名的成员函数,也不会冲突。因为名字冲突只发生在同一个域中,不同域可以有相同名字

  那当成员函数的声明和定义分离时,即声明在类内,定义在类的外面,又该如何定义函数呢?

class Date
{
public:
	void Init(int year, int month, int day);


private:
	int _year;
	int _month;
	int _day;
};

void Init(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

  
  我们知道,任何一个变量,编译器都会去找他的出处(声明/定义)。编译器默认只会在全局域或当前函数局部域去找,并不会去类域中找。那怎么办呢?我们告诉他去指定的类域中找就行了。

  • 在类体外定义成员时,需要使用 : : 作用域操作符 指明成员属于哪个类域
class Date
{
public:
	void Init(int year, int month, int day);


private:
	int _year;
	int _month;
	int _day;
};

void Date::Init(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

  这样就行了

  • 类域影响的是编译的查找规则
      
    上述程序 I n i t Init Init 如果不指定类域 D a t e Date Date,那么编译器就把 I n i t Init Init 当成全局函数,那么编译时,找不到 _ y e a r year year 等成员的声明/定义在哪里,就会报错。
    指定类域 D a t e Date Date,就是告诉编译器 I n i t Init Init 是成员函数,在当前域找不到的 _ y e a r year year 等成语,就会到类域中去查找。

  

2、实例化

2.1、实例化的概念

  在讲解类的实例化之前,我们先来思考一个问题

在这里插入图片描述

上述成员变量是声明还是定义呢?

答案是 声明
  对变量来说,到底是声明还是定义是看他是否有开空间开了空间的是定义;没开空间的是声明
  

int main()
{
	Date::_year = 0;
	return 0;
}

  我们直接这样访问是会报错的,因为 _ y e a r year year 只是一个声明,并没有开空间。

  那什么时候开空间呢?
  用该类型实例化出一个对象才是开空间

int main()
{
	Date d1;
	Date d2;
	Date d3;

	return 0;
}

  上述就是类的实例化,类和对象是一对多的关系,一个类可以实例化出多个对象
  
  怎么理解这个实例化呢?我们可以用图纸和实物建筑来类比

在这里插入图片描述

  类就相当于图纸,图纸上有房子上的各种信息,当不能进去住人;而实例化对象就像是依照着图纸将房子盖好,盖好的房子是可以住人的,相当于实例化开了空间。

  

2.2、对象大小

2.2.1、对象的大小包括什么

  在学习 C语言 结构体时,我们知道结构体中就存着成员,这些成员要按照内存对齐的规则去进行计算大小。类的对象中的成员变量也是如此,成员变量是存储在对象中的。
  现在的问题是:成员函数是否是存储在对象中的呢?
答案是:不需要
  
为什么呢?我们用日期类来举例

class Date
{
public :
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	} 

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

private:
	// 这⾥只是声明,没有开空间
	int _year;
	int _month;
	int _day;
};
int main()
{
	// Date类实例化出对象d1和d2
	Date d1;
	Date d2;

	d1.Init(2024, 3, 31);
	d1.Print();

	d2.Init(2024, 7, 5);
	d2.Print();

	return 0;
}

  
  上述代码中,示例化出了 d 1 d1 d1 d 2 d2 d2 两个对象
  我们给两个对象的年月日(成员变量)初始化了不同的值,所以他们的成员变量是不一样的,他们要各种存储自己的成员变量,因此成员变量肯定是存储在对象中
  
  那现在的 d 1 d1 d1 d 2 d2 d2 调用 P r i n t Print Print 函数是调用同一个函数还是不同的函数?
  很显然是同一个函数
  既然都是一样的,那在各自的对象中都存一份,是不是太浪费空间了。我要是实例化10000个对象那不是要重复存储10000份?
  我们通过汇编代码可以看到两个对象调用的都是同一个函数
  

在这里插入图片描述
  
两个 c a l l call call 指令, c a l l call call 的地址都是一样的,表明跳转的是同一个函数
  
  在这里插入图片描述
  
c a l l call call 指令跳转到 jmp 指令
  在这里插入图片描述
  
j m p jmp jmp 指令再跳转到函数

  成员函数其实是存在一个公共的区域

  既然函数不存在对象里面,那函数指针有必要存在对象里面吗?
  也是没必要的,原因还是重复存储浪费空间。
  

  • 函数指针是⼀个地址调⽤函数被编译成汇编指令[ c a l l call call 地址],其实编译器在编译链接时,就要找到函数的地址,不是在运⾏时找,只有动态多态是在运⾏时找,就需要存储函数地址,这个我们以后再学习

  

2.2.2、内存对齐规则

类的大小计算和结构体的计算是一样的,这里我们简单回顾一下。详情请看【C语言】——结构体

  • 第一个成员在与结构体偏移量为 0 的地址处。
  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
  • 注意:对齐数 = 编译器默认的一个对齐数与该成员大小的较小值
  • VS 中默认的对齐数是 8
  • 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到之间的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(函嵌套结构体的对齐数)的整数倍

  

2.2.3、空类的大小

class A
{
	public :
	void Print()
	{
		//...
	}
};
int main()
{
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

  现在有一个问题: a a a 的大小是多大呢?
  
运行结果:

在这里插入图片描述

  为什么该对象没有成员变量还有 1 字节的大小呢
  这里的 1 为了占位
  因为如果一个空间对不给,怎么证明这个对象存在过呢,所以这里给了1个空间大小,纯粹是为了占位表示对象存在
  

3、 t h i s this this 指针

class Date
{
public :
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	} 

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;

	d1.Init(2024, 3, 31);
	d1.Print();

	d2.Init(2024, 7, 5);
	d2.Print();

	return 0;
}

  现在,我们知道 d 1 d1 d1 d 2 d2 d2 调用的都是同一个 I n i t Init Init 函数和 P r i n t Print Print 函数,那既然是同一个函数为什么能打印出各自的成员变量呢?他们是怎么区分 d 1 d1 d1 d 2 d2 d2 的呢?

在这里插入图片描述

  
  C++中,给了一个隐含的 t h i s this this指针 解决这个问题

  • 编译器编译后,类的成员函数默认会在形参的第一个位置,增加一个当前类类型的指针,叫做 t h i s this this指针。比如 D a t e Date Date 类的 I n i t Init Init 的真实原型为: void Init(Date* const this, int year,int month, int day)
  • 类的成员函数中访问成员变量,本质是通过 t h i s this this 指针访问的,如 I n i t Init Init 函数中给 _ y e a r year year 赋值, this->_year = year;
  • C++ 规定不能在实参和形参的位置显示的写 t h i s this this指针(编译时编译器会处理),但是可以在函数体内显示使用 t h i s this this 指针

  
  因此,上述代码底层是这样的:

class Date
{
public:
	void Init(Date* const this, year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	void Print(Date* const this)
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;

	d1.Init(&d1, 2024, 3, 31);
	d1.Print(&d1);

	d2.Init(&d2, 2024, 7, 5);
	d2.Print(&d2);

	return 0;
}

:这只是底层,实际代码是不允许这样写的。因为 t h i s this this 指针不能在实参和形参显示写;但在函数体内可以使用 this 指针
  
  
那么 t h i s this this指针是存在哪一个区域的呢?

在这里插入图片描述

  首先,肯定不是对象里面。因为我们前面讲解对象大小时,并没有计算 t h i s this this 指针
  我们来看, t h i s this this 指针是一个形参,那形参是存在哪里的呢?
  答案是:
  但这答案也不完全对。
  因为 t h i s this this 指针需要频繁调用,因此有些编译器(如VS)会对其进行优化,放在寄存器

  

4、练习

4.1、题一

下面程序的运行结果是?
A、编译报错    B、正常运行    C、运行崩溃

class A
{
	public :
	void Print()
	{
		cout << "A::Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

  首先把 A 排除了,因为上述程序就算出错那也是因为空指针的问题出错,对空指针的解引用什么时候是编译报错呢?
  
  这题的答案:B

  我们来看p->Print();,这句代码转换成汇编指令是: c a l l call call 指令 -> j m p jmp jmp 指令 -> P r i n t Print Print函数;那 P r r i n t Prrint Prrint 函数在哪呢?在公共代码区,并不在对象中;同时 P r i n t Print Print函数需要传递 t h i s this this 指针,这里传的是 p p p,即 n u l l p t r nullptr nullptr
  
  这一切都没有问题。虽然传递了 n u l l p t r nullptr nullptr t h i s this this 指针,但是函数内并没有对其进行解引用
  我们不要看到对象调用函数:p->Print();就以为是对 n u l l p t r nullptr nullptr 进行了解引用,我们要关注代码的底层
  那为什么需要对象取调用呢?因为 P r i n t Print Print 是其成员函数,在其类域之中,它要过编译那关,语法那关

  

4.2、题二

下面程序的运行结果是?
A、编译报错    B、正常运行    C、运行崩溃

class A
{
	public :
	void Print()
	{
		cout << "A::Print()" << endl;
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

答案:C

  这题与上题的区别是 P r i n t Print Print 函数中多了cout << _a << endl;
  前面的步骤都是与上题一样,但到了cout << _a << endl;语句时,要对 t h i s this this 指针进行解引用cout << this->_a << endl;,因为 t h i s this this 指针是空指针,对空指针进行解引用自然就运行崩溃啦

  
  
  
  
  


  好啦,本期关于类和对象的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!

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

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

相关文章

【Hot100】LeetCode—1143. 最长公共子序列

目录 题目1- 思路2- 实现⭐最长公共子序列——题解思路 3- ACM 实现 题目 原题连接&#xff1a;1143. 最长公共子序列 1- 思路 模式识别1——> 求子序列问题 ——> dp数组定义为 i-1 和 j-1 动规五部曲 1- 创建dp数组 dp[i][j]&#xff0c;代表以 i-1 结尾的 text1 和…

“外挂”——逆向软件的分析与破解

本文来源无问社区&#xff0c;更多实战内容&#xff0c;渗透思路可前往查看http://www.wwlib.cn/index.php/artread/artid/11458.html#maodian1 前言&#xff1a; “外挂”的制作离不开软件的分析破解&#xff0c;这平时做ctf中的逆向题是有⼀定的差别的。最直观的区别体现在…

Leetcode 438. 找到字符串中所有字母异位词(java实现)

解题思路&#xff1a;滑动窗口。 异位词的典型解题方法就是用数组来统计出现的个数。本题也不例外。 直接上代码来进行讲解&#xff1a; public List<Integer> findAnagrams(String s, String p) {//初始化返回数组List<Integer> res new ArrayList<>();if …

百问网全志T113-PRO LVGL环境配置

运行LVGL示例 启动开发板 ​ 按要求接入电源或Type-c数据线&#xff0c;拨动拨码开关&#xff0c;将开发板上电 运行LVGL示例 ​ 打开串口终端软件&#xff0c;这里我使用MobaXterm软件演示&#xff0c;选择开发板的串口终端号&#xff0c;可以在设备管理中查看 这里我的串…

喜加一!望繁信科技再摘「2023年度新锐技术品牌奖」

1月31日&#xff0c;望繁信科技再次获颁由全球知名科技社区InfoQ评选的「2023年度新锐技术品牌奖」。这是InfoQ连续第二年将该奖项授予望繁信科技&#xff0c;用以肯定过去一年中&#xff0c;望繁信科技在流程挖掘与智能领域的技术创新与业务价值创造。 InfoQ在颁奖词中写到&…

【STM32】GPIO口以及EXTI外部中断

个人主页~ 有关结构体的知识在这~ 有关枚举的知识在这~ GPIO口以及EXTI外部中断 GPIO一、简介二、基本结构三、输入输出模式1、输入模式&#xff08;1&#xff09;上拉输入&#xff08;2&#xff09;下拉输入&#xff08;3&#xff09;浮空输入&#xff08;4&#xff09;模拟输…

【Python】面向对象的程序设计

一、面向对象的介绍 1.对象 对象是一种抽象概念&#xff0c;表示客观世界存在的实物&#xff0c;现实世界中能够看到的、触碰到的都可以成为对象&#xff0c;如&#xff1a;人、大象、小猫等。 对象通常分为两个部分&#xff0c;即静态部分和动态部分。静态部分为“属性”&a…

UE4 SLUA IOS打包报错解决办法

IOS打包报错&#xff1a;Fatal error "lua.h" file not found &#xff1a; SLua Unreal 在IOS远程打包编译的时候 Exteral没有copy过去&#xff0c;导致lua.h文件报错找不到&#xff0c;看了网上也没有写解决办法 错误信息截图&#xff1a; github上也有很多遇到改…

【每日一题】【动态规划(DP) 】【分治 迭代】“葡萄城杯”牛客周赛 Round 53 D题 小红组比赛 C++

“葡萄城杯”牛客周赛 Round 53 D题 小红组比赛 题目背景 “葡萄城杯”牛客周赛 Round 53 题目描述 小红希望出一场题目&#xff0c;但是他的实力又不够&#xff0c;所以他想到可以从以前的比赛中各抽一题&#xff0c;来组成一场比赛。不过一场比赛的难度应该是有限制的&a…

【nginx】nginx日志出现on文件

问题描述 生产发现容器里多出了一个on文件&#xff0c;非常大。 去看nginx配置已经这样保持16个月了&#xff08;已经去掉其他无关内容&#xff09; 原因解释 这个问题是因为nginx配置了access_log on; 有两个知识点&#xff1a; 1.access_log只有off的特殊值&#xff0c…

三菱电火花设备采集

三菱电火花机器一般情况下应该很少能见到,但在模具行业应该说是一种常见的加工设备。 一、通过官方手册采集数据 1.资料使用 连接方式: 这里重点关注下端口是1112 这里主要讲NC的状态转换 我们重点关注的是状态相关命令,手册中还支持NC程序上传和下载,感兴趣的话可以研究…

排序算法:堆排序,golang实现

目录 前言 堆排序 代码示例 1. 算法包 2. 堆排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 堆排序的思想 堆排序的实现逻辑 1. 构建最大堆 2. 排序 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据…

数据库——战德臣

1. 数据存储体系 1.1 计算机系统的存储体系 1.将不同性价比的存储组织在一起&#xff0c;满足高速的、大容量、低价格需求 2.CPU与内存直接交换信息&#xff0c;按存储单元&#xff08;存储字&#xff09;进行访问 3.外存按存储块进行访问&#xff0c;其信息先装入内存&…

NSSCTF-GDOUCTF 2023新生赛

[GDOUCTF 2023]hate eat snake 考察&#xff1a;js代码审计 打开题目&#xff0c;发现需要坚持60秒&#xff0c;那么简单的一个思路就是修改得分的变量>60即可 办法1&#xff1a;修改变量 右键查看源代码&#xff0c;之后发现有一个snake.js的文件&#xff0c;ctrlf搜索i…

健康小贴士丨中考考生怎么吃得好?

文章目录 引言三餐最佳的进食时间引言 中考正值初夏,气温急剧升高,食物易滋生细菌,发生食物中毒的风险也随之增加,医生建议 选择新鲜的食材,煮熟煮透,现吃现做,尽量不食用剩饭剩菜;不在路边露天摊点、不到无证和食品安全状况差的餐馆用餐;尽量减少在外就餐和点外卖的…

客服中心:高效知识库管理,6步提高70%用户体验

在当今快节奏的商业环境中&#xff0c;客服中心作为企业与客户沟通的重要桥梁&#xff0c;其运作的顺畅与否直接影响着客户的满意度和忠诚度。而知识库作为客服中心的核心资源之一&#xff0c;其管理水平的高低更是直接影响着客服的工作效率和问题解决能力。本文将深入探讨一系…

Django之JsonResponse对象

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 在Django框…

“LangChain实战:探索回调函数的应用

前言 毫无疑问&#xff0c;2024将是人工智能丰收年&#xff0c;开始寒假的我&#xff0c;准备先把LangChain捋一遍。 这篇文章来学习下callback机制&#xff0c; 之前聊过AutoGen的callback机制&#xff0c;我们来对比下。 回调和异步 作为js开发者&#xff0c;对于回调函数…

springboot智能健康管理平台-计算机毕业设计源码57256

摘要 在当今社会&#xff0c;人们越来越重视健康饮食和健康管理。借助SpringBoot框架和MySQL数据库的支持&#xff0c;开发智能健康管理平台成为可能。该平台结合了小程序技术的便利性和SpringBoot框架的快速开发能力&#xff0c;为用户提供了便捷的健康管理解决方案。 通过智能…

无线磁吸充电宝哪个牌子值得入手?什么牌子磁吸充电宝性价比高?

在当下科技日新月异的时期&#xff0c;无线磁吸充电宝成为了众多电子设备用户的得力助手。然而&#xff0c;面对市场上众多品牌和型号的无线磁吸充电宝&#xff0c;消费者常常陷入选择的困境&#xff1a;到底哪个牌子值得入手&#xff1f;什么牌子的磁吸充电宝性价比高&#xf…