【C++】类和对象——默认成员函数(下)

news2024/11/26 8:29:08

目录

  • 前言
  • 拷贝构造
    • 1.概念
    • 2.特征
    • 3.总结
  • 赋值重载
    • 运算符重载
    • 赋值运算符重载
      • 探讨传引用返回和传值返回的区别
  • const成员
  • 取地址及const取地址操作符重载

请添加图片描述

前言

  上一讲我们已经说了关于C++的默认成员函数中的两个——构造和析构函数。所谓默认成员函数也就是:用户没有显示定义实现时,编译器会自动生成的成员函数。
6个默认成员函数如下:

  1. 构造函数(主要完成初始化操作)
  2. 析构函数(主要完成清理操作)
  3. 拷贝构造(使用同类对象初始化对象)
  4. 赋值重载(把一个对象赋值给另一个对象)
  5. 取地址重载
  6. const取地址操作符重载

  下面我们来介绍剩下四个默认成员函数。

拷贝构造

1.概念

  只有单个形参,该形参是对本类对象类型对象的引用(一般用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

class Date
{
public:
	Date(int year, int month, int day)//用初始化列表做构造函数
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	Date(const Date& d)//拷贝构造函数,不写编译器会默认生成
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year = 2024;
	int _month = 7;
	int _day = 15;
};

int main()
{
	Date d1(2024, 7, 15);
	Date d2(d1);
	Date d3 = d1;
	//拷贝构造的形式
	return 0;
}

Date d2(d1);
Date d3 = d1;
是拷贝构造的两种形式,都是用同类型对象拷贝初始化

为了防止有人在写拷贝构造函数时会将其写成:
Date(Date& d)
{
d._year = _year;
d._month = _month;
d._day = _day;
}
所以我们在传入参数时增加const,使其不被修改,也就变成了:Date(const Date& d)

2.特征

拷贝构造函数也是特殊的成员函数,也包括一些独有的特性。

  1. 拷贝构造函数是构造函数的一种重载形式,所以拷贝构造函数是构造函数的一种特殊的形式,也拥有构造函数的特性

  1. 拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器会报错,因为它会引发无穷递归
      下面我们来验证一下为何一定要用带引用的参数。
    首先我们要明白一个点,函数调用时需要传参,内置类型直接传参,但是对于自定义类型需要调用拷贝构造才能完成
    在这里插入图片描述
    所以当你调用拷贝构造没有用引用传参时,编译器会一直调用拷贝构造函数,形成无限递归,当然现在编译器也会通过报错来告诉你不能直接传类类型的参数,如下:
    在这里插入图片描述

  1. 若未显示定义,编译器会生成默认的拷贝构造函数,默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫浅拷贝,也叫值拷贝

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式拷贝的,而自定义类型是调用其拷贝构造函数完成的。

  1. 编译器生成的默认拷贝构造已经可以完成字节序的值拷贝了,那还需要显示定义吗,我们来看看Stack栈这个类:
typedef int DataType;
class Stack
{
public:
	Stack(int capacity = 10)
	{
		_arr = (DataType*)malloc(capacity * sizeof(DataType));
		if (_arr == nullptr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		_arr[_size++] = data;
	}
	~Stack()
	{
		if (_arr)
		{
			free(_arr);
			_arr = nullptr;
			_size = 0;
			_capacity = 0;
		}
	}

private:
	DataType* _arr;
	int _size;
	int _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);

	Stack s2(s1);
	return 0;
}

  在以上代码中,我们简单写了一个栈,我们没有显示写拷贝构造函数,编译器会默认生成,但是我们发现编译器并不能通过该程序,会报一个错误:
在这里插入图片描述
  出现这个错误的原因也比较多,但是根据我们的代码,问题应该出现在创建对象时的内存分配问题上,也就是s2这个对象和s1这个对象两个内存是同一个位置,在后面析构时会出错,下面我们来具体介绍了解一下。
在这里插入图片描述
  我们通过调试发现,s1和s2的地址是一样的,它们指向的是同一块空间
在这里插入图片描述
  s1对象调用构造函数创建,且放入了4个元素1 2 3 4。
  s2对象使用s1进行拷贝构造,而Stack类没有显示定义拷贝构造函数,则编译器自动生成默认的拷贝构造,是值拷贝,也就是将s1中的内容原封不动拷贝到s2中,因此s1和s2指向同一块空间
  当程序退出时,会调用析构函数对内存进行清理,即s2和s1要消耗,先构造的后析构销毁,因此s2先销毁,此时它已经将指向的内存空间释放了,但s1并不知道,s1会继续销毁,此时会将同一块空间再次释放,一块空间多次释放,就会导致程序崩溃
  因此我们对于栈这类有资源申请的类,需要自己显示定义拷贝构造函数,如下:

typedef int DataType;
class Stack
{
public:
	Stack(int capacity = 10)
	{
		_arr = (DataType*)malloc(capacity * sizeof(DataType));
		if (_arr == nullptr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	Stack(const Stack& st)//显示定义拷贝构造函数
	{
		_arr = (DataType*)malloc(st._capacity * sizeof(DataType));
		if (_arr == nullptr)
		{
			perror("malloc申请空间失败");
			return;
		}
		memcpy(_arr, st._arr, st._size * sizeof(DataType));
		_size = st._size;
		_capacity = st._capacity;
	}
	void Push(const DataType& data)
	{
		_arr[_size++] = data;
	}
	bool Empty()
	{
		return _size == 0;
	}
	DataType Top()
	{
		return _arr[_size - 1];
	}
	void Pop()
	{
		--_size;
	}

	~Stack()
	{
		if (_arr)
		{
			free(_arr);
			_arr = nullptr;
			_size = 0;
			_capacity = 0;
		}
	}

private:
	DataType* _arr;
	int _size;
	int _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	
	Stack s2(s1);
	s2.Push(5);
	s2.Push(6);
	cout << "拷贝后:" << endl;
	cout << "s2:";
	while (!s2.Empty())
	{
		cout << s2.Top() << " ";
		s2.Pop();
	}
	cout << endl;
	cout << "s1:";
	while (!s1.Empty())
	{
		cout << s1.Top() << " ";
		s1.Pop();
	}
	cout << endl;
	return 0;
}

结果如下:
在这里插入图片描述
  我们发现,对栈s2进行插入元素,也没有改变s1,因为此时两者的地址不同,也就互不影响,这也叫深拷贝。

注意:类中如果没有涉及资源申请时,拷贝构造函数写不写都可以,但如果涉及资源申请,就必须要写拷贝构造函数,否则就是浅拷贝,编译器会报错。

补充一小点:
  为了提高程序效率,一般进行对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用用引用。

3.总结

对于拷贝构造函数的总结如下:

  1. 如果没有资源管理,一般情况下不需要写拷贝构造,使用默认生成的拷贝构造就可以,如:Date类。
  2. 如果都是自定义类型成员,内置类型没有指向资源,也用默认生成的拷贝构造就可以,例如:MyQueue。
  3. 一般情况下,不需要显示写析构函数,就不需要写拷贝构造。
  4. 如果内部有指针或者有指向资源的类型,需要显示写析构函数,通常要显示写构造完成深拷贝,如Stack,Queue,List等。

赋值重载

运算符重载

  我们都知道类型分为两种,一种是内置类型,一种是自定义类型,编译器对于内置类型的各种运算是了如指掌的,但是它不知道自定义类型要如何加减乘除,此时我们就引入了运算符重载,它是一个具有特殊函数名的函数。
->函数名为:关键字operator后面接需要重载的运算符符号,如operator+。
->函数形式:返回值类型 operator操作符(参数列表)
使用运算符重载时有几个需要注意的点:

  • 不能通过连接其他符号来创建新的操作符,如operator@,这是错误的。
  • 重载运算符必须有一个类类型的参数,如int operator+(int i, int j);这也是错误的。
  • 操作符是几目则参数个数就有几个,如+ 是双目操作符,参数个数就有两个,++是单目操作符,参数个数就是一个。
  • 有五个运算符是不能进行重载的:.*(调用函数成员指针)、::(域作用限定符)、sizeof?:(三目操作符)、.(对象.成员)这五个。
    下面我们来尝试写写operator==这个函数:
class Date
{
public:
//private:
	int _year = 2024;
	int _month = 7;
	int _day = 18;
};

bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}

void Test()
{
	Date d3(2024, 3, 10);
	Date d4(2024, 7, 18);
	cout << (d3 == d4) << endl;
	cout << operator==(d3, d4) << endl;
}

  对于运算符重载函数,既可以直接写出来判断如:(d3 == d4) ,也可以直接显示调用:operator==(d1,d2)。如果直接写出来,编译器也会转换成operator==(d1,d2),从底层汇编来讲二者是一样如,如下面的反汇编码所示:
在这里插入图片描述
  我们发现,我们将operator==重载成了全局函数,但是这样又有问题出现了,我们发现只有将私有成员函数将其变为公有,才能够使用,那这就破坏了代码的一个封装性。那么该如何解决呢,有以下几个办法可以解决:

  • 提供这些成员的get和set函数
    例如:
class Date
{
public:
	int GetYear() const
	{
		return _year;
	}
	int GetMonth() const
	{
		return _month;
	}
	int GetDay() const
	{
		return _day;
	}
private:
	int _year = 2024;
	int _month = 7;
	int _day = 18;
};

bool operator==(const Date& d1, const Date& d2)
{
	return d1.GetYear() == d2.GetYear()
	    && d1.GetMonth() == d2.GetMonth()
	    && d1.GetDay() == d2.GetDay();
}

void Test()
{
	Date d3(2024, 3, 10);
	Date d4(2024, 7, 18);
	cout << (d3 == d4) << endl;
}

  此时同样可以调用,至于函数后面加的const我们下面会再讲解。


  • 写成友元函数(后面会讲到)
  • 重载成成员函数
    重载成成员函数时需要注意的是不能直接将其放入到成员函数中,是因为成员函数的参数有隐含的this指针,直接放入会导致参数过多而报错,因此我们要减少参数再放入,如下所示:
class Date
{
public:
	bool operator==(const Date& d1)
	{
		return _year == d1._year
			&& _month == d1._month
			&& _day == d1._day;
	}

private:
	int _year = 2024;
	int _month = 7;
	int _day = 18;
};


void Test()
{
	Date d3(2024, 3, 10);
	Date d4(2024, 7, 18);
	cout << (d3 == d4) << endl;
}

  但是要注意的是,当我们将其重载成了成员函数,就不能显示调用了,因为参数过多,会报错。


赋值运算符重载

  上面说的是运算符重载,现在我们来说运算符重载中的一个特例:赋值运算符重载,它是六个默认成员函数中的第四个,它是把一个已经存在的对象赋值给另一个已经存在的对象,我们来详细剖析这个函数。

  1. 赋值运算符的重载格式。
  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T& ,返回引用可以提高返回效率,有返回值的目的是为了支持连续赋值。
  • 检测是否自己给自己赋值
  • 返回*this,要符合连续赋值的含义。

当我们写一个Date类,显示定义赋值运算符重载:

class Date
{
public:
   Date(int year, int month, int day)//用初始化列表做构造函数
   	:_year(year)
   	, _month(month)
   	, _day(day)
   {
       cout << "Date(int year, int month, int day)" << endl;
   }
   Date(const Date& d)//拷贝构造函数,不写编译器会默认生成
   {
   	_year = d._year;
   	_month = d._month;
   	_day = d._day;
   	cout << "Date(const Date& d)" << endl;
   }

   Date& operator=(const Date& d)//显示定义赋值运算符重载
   {
   	if (this != &d)//判断this指向的地址和d的地址是否相同,相同则表明是自己给自己赋值
   	//加了判断条件就能防止自己给自己赋值,避免更多的损耗。
   	{
   		_year = d._year;
   		_month = d._month;
   		_day = d._day;
   	}
   	return *this;
   }

private:
   int _year = 2024;
   int _month = 7;
   int _day = 15;
};

int main()
{
   Date d1(2024, 7, 15);
   Date d2(2024, 7, 18);
   Date d3(2024, 7, 20);

   d1 = d2 = d3;//一个已经存在的对象赋值给另一个已经存在的对象
//此时我们将d3的日期值先赋值给了d2,然后又赋值给了d1.
   return 0;
}

如果是下面这段代码:
Date d4 = d1;
则这个是拷贝构造,因为这是一个已经存在的对象,拷贝给另一个要创建初始化的对象。
要注意区分二者。

  当我们定义的赋值重载函数没有返回值类型时则不能支持连续赋值,如下所示:

	void operator=(const Date& d)
   {
   	if (this != &d)
   	{
   		_year = d._year;
   		_month = d._month;
   		_day = d._day;
   	}
   }

在这里插入图片描述

探讨传引用返回和传值返回的区别

  我们再来考虑第二点,传引用返回和不传引用返回的区别是什么,什么时候可以用传引用返回,什么时候不可以。
  当我们使用引用返回时:
在这里插入图片描述
  可以看到,编译器只对三个对象进行了构造,而没有调用拷贝构造。
  但是当使用传值返回时:
在这里插入图片描述
  编译器不仅对三个变量进行了构造,还在赋值时进行了两次拷贝构造,由此我们可以看出,使用引用返回可以减少拷贝构造次数,减少消耗。
  那我们什么时候能用引用返回呢,我们来举个例子就知道了:

Date func()
{
	Date d(2024, 7, 20);
	return d;
}

int main()
{
	const Date& ref = func();
	ref.Print();
	return 0;
}

  我们定义了一个func函数,传值返回,并将结果打印出来,如下:
在这里插入图片描述

由结果可以看出,它先通过构造函数构造了对象d,接收值打印后进行了析构,析构的是对象d。
但实际上,编译器在进行传值返回时,会将d进行一次拷贝构造出来一个临时对象,这个临时对象具有常性,ref引用的就是这个临时对象,所以需要加const。
在这里插入图片描述
但是由于编译器的优化,将构造和拷贝构造直接优化成了只剩构造,所以我们没能看出来有拷贝构造的存在,如果我们使用的编译器是vs2019,则可以看得出来。

  但是如果我们使用引用返回:
在这里插入图片描述
  我们发现,得出的结果并不是我们想要的结果,是因为返回对象是一个局部的临时对象,ref和d的地址是一样的,出了func的作用域,d就析构销毁了,所以当我们打印ref时得到的值会是随机值。
  而在原来的代码中,我们返回的是this,用引用返回,是因为this在main作用域中就创建出来了,出了main才会被销毁,而出operator=这个函数是不会被销毁的,因此可以用传引用返回。

总结来说
返回对象是一个局部对象或临时对象时,出了函数作用域会被析构销毁的话,则不能用引用返回。引用返回可以减少拷贝,但是引用返回存在风险,要看出了函数作用且对象还在,则可以使用引用返回。


  1. 赋值运算符不能重载成全局函数。

  当我们想把赋值运算符重载成全局函数时,全局函数不存在this指针,则需要用两个参数传参,如下所示:

class Date
{
public:
	Date(int year, int month, int day)//用初始化列表做构造函数
		:_year(year)
		, _month(month)
		, _day(day)
	{}
//private:
	int _year = 2024;
	int _month = 7;
	int _day = 15;
};
Date& operator=(Date& left, Date& d)
{
	if (&left != &d)
	{
		left._year = d._year;
		left._month = d._month;
		left._day = d._day;
	}
	return left;
}

  当我们将其重载成全局函数时,需要考虑私有成员变量的时候,这里为了方便演示,将其变成了公有。此时编译器会报错:
error C2801: “operator =”必须是非静态成员。
  原因也很简单:赋值运算符如果不显示实现,编译器会生成一个默认的,此时用户在类外自己实现的这个全局的赋值运算符重载就会和编译器在类中生成的默认赋值运算符重载冲突,所以赋值运算符重载只能是类的成员函数。


  1. 用户没有显示实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字拷贝

  值得注意的是:内置类型成员变量是可以直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。这点与拷贝构造是类似的。

const成员

  将const修饰的成员函数称为const成员函数,const修饰类成员函数,实际修饰的是该成员函数隐含的this指针,表明在该函数成员中不能对类的任何成员进行修改。
  编译器对const成员函数的处理如下:
在这里插入图片描述
  对于const,就会存在一个权限的问题,要如何使用才不会报错:
在这里插入图片描述
最后还有几个可以思考的问题:

  • const对象可以调用非const成员函数吗?
    ->不可以,这属于权限放大
  • 非const对象可以调用const成员函数吗?
    ->可以,这属于权限缩小
  • const成员函数内可以调用其他非const成员函数吗?
    ->不可以,这属于权限放大
  • 非const成员函数内可以调用其他const成员函数吗?
    ->可以,这属于权限缩小

取地址及const取地址操作符重载

  这是最后两个默认成员函数,一般不用重新定义,编译器会默认生成,我们在实践中用的也比较少。
  使用如下所示:

class Date
{
public:
	Date(int year, int month, int day)//用初始化列表做构造函数
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	Date* operator&()
	{
		return this;
	}
	const Date* operator&() const
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 7, 15);
	const Date d2(2024, 7, 20);
	cout << &d1 << endl;
	cout << &d2 << endl;
	return 0;
}

  结果则会生成这两个对象的地址。
  这两个运算符一般不需要重载,使用编译器生成的默认取地址重载即可,只有特殊情况才需要重载,如想让别人获取到指定的内容。

  今天的内容到此结束啦,感谢大家观看,如果大家喜欢,希望大家一键三连支持一下,如有表述不正确,也欢迎大家批评指正。

请添加图片描述

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

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

相关文章

《背包乱斗》为什么好玩 苹果电脑怎么玩《背包乱斗》游戏 mac怎么玩steam windows游戏

在当今竞争激烈的游戏市场中&#xff0c;《背包乱斗》以其独特的魅力在众多作品中脱颖而出&#xff0c;吸引了大量玩家的关注和喜爱。其创新的游戏机制和不断迭代的内容&#xff0c;加之出色的视觉效果和社区建设&#xff0c;使其成为了游戏界的一股清流。 一、《背包乱斗》为…

钡铼EdgeIO系统BL206对接MQTT、Modbus TCP、OPC UA

钡铼EdgeIO系统BL206提供双网口支持交换机级联功能&#xff0c;支持标准MQTT协议、Modbus TCP协议、OPC UA协议&#xff0c;由耦合器与IO模块组成&#xff0c;采用Web配置&#xff0c;内置云驱动、可编程逻辑控制功能&#xff0c;用户点击即可连接云平台。耦合器自带诊断功能&a…

计算机三级嵌入式笔记(一)—— 嵌入式系统概论

目录 考点1 嵌入式系统 考点2 嵌入式系统的组成与分类 考点3 嵌入式系统的分类与发展 考点4 SOC芯片 考点5 数字&#xff08;电子&#xff09;文本 考点6 数字图像 考点7 数字音频与数字视频 考点8 数字通信 考点9 计算机网络 考点10 互联网 考纲&#xff08;2023&am…

某宝同款度盘不限速后台系统源码

简介&#xff1a; 某宝同款度盘不限速后台系统源码&#xff0c;验证已被我去除&#xff0c;两个后端系统&#xff0c;账号和卡密系统 第一步安装宝塔&#xff0c;部署卡密系统&#xff0c;需要环境php7.4 把源码丢进去&#xff0c;设置php7.4&#xff0c;和伪静态为thinkphp…

新手小白的pytorch学习第七弹------分类问题模型

目录 1. 准备分类数据1.1 输入和输出的形状 shape1.2 将数据转换为张量&#xff0c;同时将我们的数据集转换为训练集和测试集 2 创建模型方法一&#xff1a;自定义forward()方法二&#xff1a;nn.Sequential()方法三&#xff1a;自定义forward()nn.Sequential() 用 pytorch 使用…

【Leetcode】十六、深度优先搜索 宽度优先搜索 :二叉树的层序遍历

文章目录 1、深度优先搜索算法2、宽度优先搜索算法3、leetcode102&#xff1a;二叉树的层序遍历4、leetcode107&#xff1a;二叉树的层序遍历II5、leetcode938&#xff1a;二叉搜索树的范围和 1、深度优先搜索算法 深度优先搜索&#xff0c;即DFS&#xff0c;从root节点开始&a…

Cadence23学习笔记(七)

三种信号联通的方式&#xff1a; 如何旋转元器件&#xff1a;先像下图一样选中器件&#xff0c;之后按住快捷键R即可旋转&#xff1a; 设置栅格大小&#xff1a; 这里的栅格数值越大&#xff0c;格点越密集。 放置分页符号&#xff1a; cadence中分页的话必须放置分页符&#…

充电站新主流——分体式直流充电桩

在全球对可持续发展和环境保护的高度关注下&#xff0c;电动汽车市场的迅猛增长催生了对充电设施建设的迫切需求。为此&#xff0c;一种名为分体式充电桩的创新充电设备应运而生&#xff0c;以其卓越的性能和独特优势&#xff0c;预示着未来充电技术的新趋势。为了增进公众对分…

PY32F002B单片机 ISP 串口下载注意事项

一、PY32F002B ISP 串口下载的连接方式 仿真上的 VCC 和 GND 连接到 MCU 的 VCC 和 VSS&#xff0c; 仿真的 TX 接 MCU 的 RX&#xff0c;RX 接 MCU 的 TX。 二、因为 PY32F002B 没有 BOOT&#xff0c;需要用 ISP 串口下载的话需要下载串口引导程序。 下载这个目录下的 IAP…

FPGA实验1:简单逻辑电路

一、实验目的及要求 学习Create-SOPC实验平台的使用方法&#xff1b;熟悉Quartus II 软件平台和使用 VHDL 语言设计电路的方法&#xff1b;学习简单逻辑电路的设计、仿真和硬件测试。 二、实验原理 运用Quartus II 集成环境下的VHDL文本设计方法设计半加器&#xff0c;进行波…

摸鱼大数据——Spark Structured Steaming——物联网数据分析案例

1、数据模拟器代码 1- 创建一个topic, 放置后续物联网的数据 search-log-topic ./kafka-topics.sh --bootstrap-server node1.itcast.cn:9092,node2.itcast.cn:9092 --create --topic search-log-topic --partitions 3 --replication-factor 2 2- 将代码放置到项目中: import…

浅谈芯片验证中的仿真运行之 timescale (五)提防陷阱

一 仿真单位 timeunit 我们知道,当我们的代码中写清楚延时语句时,若不指定时间单位,则使用此单位; 例如: `timescale 1ns/1ps 则 #15 语句表示delay15ns; 例:如下代码,module a 的timescale是1ns/1ps, module b 是1ps/1ps; module b中的clk,频率是由输入参…

【LeetCode】222. 完全二叉树的个数

什么是计算机基础&#xff1f;如果本题能够用二分二进制二叉树的方式解出本题&#xff0c;那么我可以认为你的计算机基础就很好了。很久以来&#xff0c;我一直认为自己的计算机基础好&#xff0c;但是自刷题以来&#xff0c;跟网上这么多优秀的同学相比&#xff0c;我发现我实…

vxe-grid 实现配置式form搜索条件 form搜索条件框可折叠 配置式table

文章目录 效果图代码 效果图 代码 <template><div class"app-container"><vxe-grid refxGrid v-bind"gridOptions" v-if"tableHeight" :height"tableHeight"><template #billDate"{ data }"><e…

FPGA实验5:4位加法计数器

实验目的及要求 掌握时钟信号、进程和BUFFER端口的运用&#xff1b;了解计数器的设计、仿真和硬件测试&#xff0c;进一步熟悉VHDL语句、语法及应用等。 实验原理 运用Quartus II 集成环境下的VHDL文本设计方法设计4位加法计数器&#xff0c;进行波形仿真和分析、引脚分配…

【Apache Doris】周FAQ集锦:第 15 期

【Apache Doris】周FAQ集锦&#xff1a;第 15 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户…

从数据湖到湖仓一体:统一数据架构演进之路

文章目录 一、前言二、什么是湖仓一体&#xff1f;起源概述 三、为什么要构建湖仓一体&#xff1f;1. 成本角度2. 技术角度 四、湖仓一体实践过程阶段一&#xff1a;摸索阶段(仓、湖并行建设)阶段二&#xff1a;发展阶段方式一、湖上建仓(湖在下、仓在上)方式二&#xff1a;仓外…

一种优雅的方法获取PyInstaller打包Python程序的资源路径和目录路径

1、需求分析 运行Python程序的时候需要获取的资源有2种&#xff1a; 一种是固定的资源文件&#xff0c;你希望启动程序的时候可以调用的&#xff0c;比如数据库文件和图片资源文件&#xff1b;另一种是用于存储历史记录的文件&#xff0c;你希望每次打开都会改变其中的内容&am…

【机器学习】智能驱动未来:机器学习在能源效率提升与环境管理中的创新应用

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习能源环境领域的应用潜力&#x1f304;能源效率提升&#x1f3de;️环境管理⛰️具体案例…

动漫风格动漫404网站维护HTML源码

源码介绍 动漫风格动漫404网站维护HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 效果预览 源码下载 动漫风格动漫404网站维护HTML源码