类和对象:完结

news2024/11/17 23:24:29

1.再深构造函数

之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅
式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成
员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式;
每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义 初始化的地⽅
引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始 化,否则会编译报错;(初始化列表就是他们俩初始化的地方)
#include<iostream>
using namespace std;
class A
{
public:
	//如果不想让类型转换发生,可以在构造函数前加explicit函数
	/*explicit A(int a = 0)
	{
		_a1 = a;
	}*///多参数也是如此
	A(int a = 0)//单参数可以
	{
		_a1 = a;
	}
	A(int a1, int a2)
	{
		_a1 = a1;
		_a2 = a2;
	}
	A(const A& aa)
	{
		_a1 = aa._a1;
	}
	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a1 = 1;
	int _a2 = 2;
};

class Stack
{
public:
	void Push(const A& aa)//临时对象具有常性,要加const
	{
		//...
	}
private:
	A _arr[10];
	int _top;
};
int main()
{
	A aa1(1);//调用构造
	aa1.Print();
	// 隐式类型转换,类型转换会生成中间变量
	// 2先构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa2
	// 编译器遇到连续构造+拷⻉构造->优化为直接构造
	//调试观察
	A aa2 = 2;
	aa2.Print();

	A& raa1 = aa2;
	//A& aa2 = 2;可以验证:
	//并不是直接构造,会生成临时变量,具有常性
	const A& aa2 = 2;


	//真正用意:
	Stack st;
	A aa3(3);
	st.Push(aa3);
	//写起来更简单,消耗是一样的
	st.Push(3);

	//多参数:
	//A aa4 = 1, 1;//不支持
	//但是:C++11后才支持多参数转换
	A aa4 = { 1, 1 };
	const A& raa5 = { 2,2 };
	st.Push(aa4);
	st.Push({ 2,2 });
	return 0;
}

注意:初始化列表是他定义的地方,那么每个成员都会去走初始化列表,哪怕是不写

还有一类:自定义类型:

EG:

class Time
{
public:
	Time(int hour = 1)
		:_hour(hour)
	{
		cout << "Time()" << endl;
	}
private:
	int _hour;
};

不在初始化列表中定义, 不写也走:只调用Time的默认构造函数(无参/全缺省)

如果Time没有默认构造,调不到,只能自己传,爱传什么传什么:

无默认构造:

class Time
{
public:
	Time(int hour)
		:_hour(hour)
	{
		cout << "Time()" << endl;
	}
private:
	int _hour;
};
class Date
{
public:
	Date(int& xx, int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
		
		, _n(1)
		, _ref(xx)
		, _t(1)
	{}
	void Print()const
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	//声明
	int _year;
	int _month;
	int _day;

	const int _n;
	int& _ref;
	Time _t;
};

初始化列表和函数体内可以混着赋值:
EG:(初始化列表和函数体可以打配合)

Date()
	:_ptr((int*)malloc(12))
{
	//初始化列表和函数体内可以混着赋值
	if (_ptr == nullptr)
	{
		perror("malloc fail");
	}
	else
	{
		memset(_ptr, 0, 12);
	}
}
C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的 成员使⽤的;
(注:定义是有开空间,下列是声明)C++11及后
private:
	//声明,后面为缺省值->初始化列表用的
	int _year = 1;
	int _month = 1;
	int _day = 1;;
可以通过缺省函数理解,只不过是给初始化类表用的;
(结合下图理解):
尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这 个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。如果你没有给缺省值,对于没 有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有 显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构 造会编译错误;
注意与默认构造函数区分:
可以无参调用的才是默认构造:(以下并不是)
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		//, _day(day)对于内置类型,是不做处理的,可能是个随机值
	{

	}
	void Print()const
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	//声明,后面为缺省值->初始化列表用的
	int _year = 1;
	int _month = 1;
	int _day = 1;;
};

int main()
{
	
	Date d1(2024, 7, 14);
	d1.Print();

	Date d2;//会报错,所以并不是默认构造

	return 0;
}
因此:让编译器自动生成默认构造便可行:
还有:不仅仅可以给以上这种缺省值:
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;;

	int* _ptr = (int*)malloc(12);
	Time _t = 1;
初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆ 关。建议声明顺序和初始化列表顺序保持⼀致;
例题:
下⾯程序的运⾏结果是什么(D)
A. 输出 1 1
B. 输出 2 2
C. 编译报错
D. 输出 1 随机值
E. 输出 1 2
F. 输出 2 1
#include<iostream>
using namespace std;
class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}
	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2 = 2;
	int _a1 = 2;
};
int main()
{
	A aa(1);
	aa.Print();
}
因为定义是先_a2后_a1,先对_a2进行初始化,这时候_a1的缺省值还没发现,给_a2的初始化就是编译器自己决定的,为_a1的随机值,将_a1的值给了_a2,再到_a1,将1的值给了_a1,所以answer是D!(调试很快发现)
总结:尽可能写初始化列表
每个成员都要走初始化列表,每个构造函数都有初始化列表
1.在初始化列表初始化的成员:直接用;(显示写)
2.没有在初始化列表的成员(不显示写)
----a.声明的地方有缺省值用缺省值
----b.没有缺省值
--------x.内置类型:不确定,看编译器,大概率是随机值
--------y.自定义类型:调用默认构造,没有默认构造就编译报错
3.引用,const没有默认构造的自定义,必须在初始换列表初始化
4.不要把初始化列表和默认构造扯上关系
5. 初始化列表中按照成员变量在类中声明顺序(在内存中存放的顺序)进⾏初始化
6.声明中的缺省值是给初始化列表用的,缺省值是不走初始化列表的

2.类型转换

C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数
构造函数前⾯加explicit就不再⽀持隐式类型转换

3.static成员

⽤static修饰的成员变量,称之为静态成员变量, 静态成员变量⼀定要在类外进⾏初始化 ;
#include<iostream>
using namespace std;
class A
{
public:
	A()
	{
		++_scount;
	}
	A(const A& t)
	{
		++_scount;
	}
	~A()
	{
		--_scount;
	}
private:
	// 类⾥⾯声明
	static int _scount;
};
// 类外⾯初始化
int A::_scount = 0;
int main()
{
	return 0;
}
静态成员变量为当前类的所有对象所共享, 不属于某个具体的对象 ,不存在对象中,存放在静态区;
⽤static修饰的成员函数,称之为静态成员函数, 静态成员函数没有this指针 ;
如果:_scount是私有的,那么指定类域的方式就行不通了,这时候就可以提供一个静态的成员函数:
static int GetACount()
{
	return _scount;
}
静态成员函数中可以访问其他的静态成员,但是 不能访问⾮静态 的,因为没有this指针;
static int GetACount()
{
	_a++;//报错//不能访问⾮静态的,因为没有this指针
	return _scount;
}
⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数;
void func()
{
	cout << _scount << endl;
	cout << GetACount() << endl;
}
突破类域就可以访问静态成员,可以通过"类名::静态成员"或者"对象.静态成员"来访问静态成员变量和静态成员函数;
cout << A::GetACount() << endl;
cout << a1.GetACount() << endl;
静态成员也是类的成员,受public、protected、private 访问限定符的限制;(类里面定义的静态成员变量某种程度上可以理解为静态的全局,只是受类域的限制,也就是他的生命周期是全局的,且不属于某个对象,严格来说只能在所在的类里面使用,类外面也行,只是受访问限定符的限制)
静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表;

4.友元

友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯;
外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数;
友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制;
⼀个函数可以是多个类的友元函数;(我不仅仅和你,还要和别人做朋友)
#include<iostream>
using namespace std;
// 前置声明,不然则A的友元函数声明编译器不认识B//-----注意点
class B;//-----解决点
class A
{
	// 友元声明
	friend void func(const A& aa, const B& bb);//-----问题点
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
	// 友元声明
	friend void func(const A& aa, const B& bb);
private:
	int _b1 = 3;
	int _b2 = 4;
};
void func(const A& aa, const B& bb)
{
	cout << aa._a1 << endl;//~~~~~~~~~~~~~~~~~~~~~~~~~
	cout << bb._b1 << endl;//一个函数成为多个类的友元
}
int main()
{
	A aa;
	B bb;
	func(aa, bb);
	return 0;
}

友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员;

#include<iostream>
using namespace std;
class A
{
	// 友元声明
	friend class B;//把B定义成A的友元类-----解决点---B的成员函数都成为了A的友元函数
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
public://B要一直访问A类的私有保护成员-----问题点
	void func1(const A& aa)
	{
		cout << aa._a1 << endl;
		cout << _b1 << endl;
	}
	void func2(const A& aa)
	{
		cout << aa._a2 << endl;
		cout << _b2 << endl;
	}
private:
	int _b1 = 3;
	int _b2 = 4;
};
int main()
{
	A aa;
	B bb;
	bb.func1(aa);
	bb.func1(aa);
	return 0;
}

友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元;

友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不一定是C的友元;
有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤;

5.内部类 

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在全局相⽐,他仅仅只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类;(内类不是属于外类的成员)
内部类默认是外部类的友元类;(我是你的朋友,所以我可以访问你的私有)
内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的 专属内部类 ,其
他地⽅都⽤不了;
#include<iostream>
using namespace std;
class A
{
private:
	static int _k;
	int _h = 1;
public:
	class B // B默认就是A的友元
	{
	public:
		void foo(const A& a)
		{
			cout << _k << endl; //OK
			cout << a._h << endl; //OK
		}
	private:
		int _b = 1;
	};
};
int A::_k = 1;
int main()
{
	cout << sizeof(A) << endl;//4:实际上只有一个_h,没带_b//B不是A的成员
	A::B b;//指定B是属于A的类域(受访问限定符限制)
	A aa;
	b.foo(aa);
	return 0;
}

6.匿名对象

⽤"类型(实参)"定义出来的对象叫做匿名对象,相⽐之前我们定义的"类型 对象名(实参)"定义出来的叫有名对象;
匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象;( 他的⽣命周期只有这⼀⾏,我们可以看到下⼀⾏他就会⾃动调⽤析构函数 )
就是为了更方便;
#include<iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
class Solution {
public:
	int Sum_Solution(int n) {
		//...
		return n;
	}
};
int main()
{
	A aa1;
	A aa2(2);
	// 不能这么定义对象,因为编译器⽆法识别下⾯是⼀个函数声明,还是对象定义
	//A aa1();
	// 但是我们可以这么定义匿名对象,匿名对象的特点不⽤取名字,
	// 但是他的⽣命周期只有这⼀⾏,我们可以看到下⼀⾏他就会⾃动调⽤析构函数
	A();
	A(1);
	// 匿名对象在这样场景下就很好⽤,当然还有⼀些其他使⽤场景,这个我们以后遇到了再说
	cout << Solution().Sum_Solution(10) << endl;//就是为了更方便

	//有名
	Solution st;
	cout << st.Sum_Solution(10) << endl;
	return 0;
}

7.对象拷贝时的编译器优化

现代编译器会为了尽可能提⾼程序的效率,在不影响正确性的情况下会尽可能减少⼀些传参和传返回值过程中可以省略的拷⻉;
如何优化C++标准并没有严格规定,各个编译器会根据情况⾃⾏处理。当前主流的相对新⼀点的编译器对于连续⼀个表达式步骤中的连续拷⻉会进⾏合并优化,有些更新更"激进"的编译还会进⾏跨⾏跨表达式的合并优化;
示例类:
#include<iostream>
using namespace std;
class A
{
public:
	A(int a = 0)
		:_a1(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa)
		:_a1(aa._a1)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a1 = aa._a1;
		}
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
    void Print()
    {
	    cout << "A::Print " << _a1 << endl;
    }
private:
	int _a1 = 1;
};
单参数类型的构造函数的隐式类型转化的优化示例:
int main()
{
	//单参数类型的构造函数的隐式类型转化
	A aa1 = 1;//构造加拷贝构造(构造临时对象,对临时对象进行拷贝构造)(因为类型转化会产生临时对象)
	//开始执行发现:编译器优化成直接拷贝
	const A& aa2 = 1;//生成临时对象,是引用,没有拷贝构造
	return 0;
}

传参优化示例:

void f1(A aa)//传值传参---会产生一个拷贝
{}
void f2(A& aa)
{}
int main()
{
	A aa1(1);//构造
	//f1(aa1);//实参传给形参进行拷贝:调用构造,拷贝构造//不会优化:一般是在连续一个步骤才有优化//但是不排除其他更激进的
	cout << endl;
	//用引用:减少拷贝构造
	f2(aa1);
	cout << endl;
	//用匿名对象:在连续过程
	f1(A(1));//优化成直接构造
	cout << endl;
	f1(1);//本意是1走隐式类型转化,生成临时对象,再拷贝构造:优化成直接构造
	cout << endl;
	return 0;
}

 传返回值优化示例:

A f3()//传值传参返回:会产生一个临时对象:因为aa出了作用域就销毁了
{
	A aa(1);
	return aa;//产生临时对象
}
//应该是aa作为局部对象,出了作用域销毁,调用~A(),由aa产生临时对象调用Print
//VS2022优化:严格来说没有生成aa,合二为一,只生成临时对象:看执行结果可推
int main()
{
	f3().Print();//因为临死对象:构造+拷贝构造//用产生的临时对象调用Print//临时对象的周期就在这一行
	cout << endl;
	return 0;
}
A f4()
{
	A aa(1);//构造
	return aa;//拷贝构造
}
//优化:省略了临时对象,VS2022更激进,连aa都省掉了建议用2019-debug观察
int main()
{
	A ret = f4();//拷贝构造
	ret.Print();	
	cout << endl;
	return 0;
}
A f4()
{
	A aa(1);//构造
	cout << "~~~~~~~~~" << endl;//构造了aa,aa充当临时对象
	return aa;//拷贝构造
}
int main()
{
	A ret;
	ret = f4();//赋值//赋值完后。临时对象析构
	ret.Print();	
	cout << endl;
	return 0;
}

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

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

相关文章

redis的使用场景

1. redis的使用场景 redis使用场景的案例&#xff1a;[1]热点数据的缓存[2]分布式锁[3]短信业务&#xff08;登录注册时&#xff09;2. redis实现注册登录功能 代码 在发送验证码时&#xff0c;先判断数据库是否有该手机号&#xff0c;有则发送验证码&#xff08;此时redis缓存…

基于微信小程序+SpringBoot+Vue的自习室选座与门禁系统(带1w+文档)

基于微信小程序SpringBootVue的自习室选座与门禁系统(带1w文档) 基于微信小程序SpringBootVue的自习室选座与门禁系统(带1w文档) 本课题研究的研学自习室选座与门禁系统让用户在小程序端查看座位&#xff0c;预定座位&#xff0c;支付座位价格&#xff0c;该系统让用户预定座位…

Jmeter三种方式获取数组中多个数据并将其当做下个接口参数入参【附带JSON提取器和CSV格式化】

目录 一、传统方式-JOSN提取器获取接口返回值 1、接口调用获取返回值 2、添加JSON提取器 3、调试程序查看结果 4、添加循环控制器 5、设置count计数器 6、添加请求 7、执行请求 二、CSV参数化 1、将结果写入后置处理程序 2、设置循环处理器 3、添加CSV文件 4、设置…

【机器学习】用Jupyter Notebook实现并探索单变量线性回归的代价函数以及遇到的一些问题

引言 在机器学习中&#xff0c;代价函数&#xff08;Cost Function&#xff09;是一个用于衡量模型预测值与实际值之间差异的函数。在监督学习中&#xff0c;代价函数是评估模型性能的关键工具&#xff0c;它可以帮助我们了解模型在训练数据上的表现&#xff0c;并通过优化过程…

IPD推行成功的核心要素(十五)项目管理提升IPD相关项目交付效率和用户体验

研发项目往往包含很多复杂的流程和具体的细节。因此&#xff0c;一套完整且标准的研发项目管理制度和流程对项目的推进至关重要。研发项目管理是成功推动创新和技术发展的关键因素。然而在实际管理中&#xff0c;研发项目管理常常面临着需求不确定、技术风险、人员素质、成本和…

PyTorch安装CUDA标准流程(可解决大部分GPU无法使用问题)

最近一段时间在研究PyTorch中的GPU的使用方法&#xff0c;之前曾经安装过CUDA&#xff0c;不过在PyTorch中调用CUDA时无法使用。考虑到是版本不兼容问题&#xff0c;卸载后尝试了其他的版本&#xff0c;依旧没有能解决问题&#xff0c;指导查阅了很多资料后才找到了解决方案。 …

uni-app声生命周期

应用的生命周期函数在App.vue页面 onLaunch:当uni-app初始化完成时触发&#xff08;全局触发一次&#xff09; onShow:当uni-app启动&#xff0c;或从后台进入前台时显示 onHide:当uni-app从前台进入后台 onError:当uni-app报错时触发,异常信息为err 页面的生命周期 onLoad…

数据治理之“财务一张表”

前言 信息技术的发展&#xff0c;伴随企业业务系统的纷纷建设&#xff0c;提升业务处理效率的同时&#xff0c;也将企业的整体主价值链流程分成了一段一段的业务子流程&#xff0c;很多情况下存在数据上报延迟、业务协作不顺畅、计划反馈不及时、库存积压占资多……都可以从数据…

20240725java的Controller、DAO、DO、Mapper、Service层、反射、AOP注解等内容的学习

在Java开发中&#xff0c;‌controller、‌dao、‌do、‌mapper等概念通常与MVC&#xff08;‌Model-View-Controller&#xff09;‌架构和分层设计相关。‌这些概念各自承担着不同的职责&#xff0c;‌共同协作以构建和运行一个应用程序。‌以下是这些概念的解释&#xff1a;‌…

深度学习趋同性的量化探索:以多模态学习与联合嵌入为例

深度学习趋同性的量化探索&#xff1a;以多模态学习与联合嵌入为例 参考文献 据说是2024年最好的人工智能论文&#xff0c;是否有划时代的意义&#xff1f; [2405.07987] The Platonic Representation Hypothesis (arxiv.org) ​arxiv.org/abs/2405.07987 趋同性的量化表达 …

OAK相机支持的图像传感器有哪些?

相机支持的传感器 在 RVC2 上&#xff0c;固件必须具有传感器配置才能支持给定的相机传感器。目前&#xff0c;我们支持下面列出的相机传感器的开箱即用&#xff08;固件中&#xff09;传感器配置。 名称 分辨率 传感器类型 尺寸 最大 帧率 IMX378 40563040 彩色 1/2.…

产品经理-简历的筛选标准(22)

什么是简历 简要地描述过往的经历—一份简历的核心要素就是介绍你所经历过的事情 因此准备简历的关键是“简”“要”二字&#xff1a; 一方面是你挑选出来的事情&#xff0c;一定是重要的、能给予你所谋求的位置提供竞争力的事情&#xff1b;另一方面是在描述这件事情的时候 要…

《Java初阶数据结构》----6.<优先级队列之PriorityQueue底层:堆>

前言 大家好&#xff0c;我目前在学习java。之前也学了一段时间&#xff0c;但是没有发布博客。时间过的真的很快。我会利用好这个暑假&#xff0c;来复习之前学过的内容&#xff0c;并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…

Golang | Leetcode Golang题解之第290题单词规律

题目&#xff1a; 题解&#xff1a; func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…

【Python实战因果推断】56_因果推理概论6

目录 Causal Quantities: An Example Bias Causal Quantities: An Example 让我们看看在我们的商业问题中&#xff0c;你如何定义这些量。首先&#xff0c;你要注意到&#xff0c;你永远无法知道价格削减&#xff08;即促销活动&#xff09;对某个特定商家的确切影响&#xf…

算法 定长按组翻转链表

一、题目 已知一个链表的头部head&#xff0c;每k个结点为一组&#xff0c;按组翻转。要求返回翻转后的头部 k是一个正整数&#xff0c;它的值小于等于链表长度。如果节点总数不是k的整数倍&#xff0c;则剩余的结点保留原来的顺序。示例如下&#xff1a; &#xff08;要求不…

数据集成工具之kettle

Kettle 是一个用于数据集成的开源工具&#xff0c;由 Pentaho 开发&#xff0c;现已由 Hitachi Vantara 维护。Kettle 的全名是 Pentaho Data Integration (PDI)&#xff0c;主要用于数据提取、转换和加载&#xff08;ETL&#xff09;过程。 1. 核心组件 Spoon: 图形化的设计工…

【MetaGPT系列】【MetaGPT完全实践宝典——多智能体实践】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、多智能体系统介绍2-4、多智能体案例分析2-4-1、构建智能体团队2-4-2、动作/行为 定义2-4-3、角色/智…

mysql面试(六)

前言 本章节详细讲解了一下mysql执行计划相关的属性释义&#xff0c;以及不同sql所出现的不同效果 执行计划 一条查询语句经过mysql查询优化器的各种基于成本和各种规则优化之后&#xff0c;会生成一个所谓的 执行计划&#xff0c;这个执行计划展示了这条查询语句具体查询方…

Qt自定义MessageToast

效果&#xff1a; 文字长度自适应&#xff0c;自动居中到parent&#xff0c;会透明渐变消失。 CustomToast::MessageToast(QS("最多添加50张图片"),this);1. CustomToast.h #pragma once#include <QFrame>class CustomToast : public QFrame {Q_OBJECT pub…