C++的第一道门坎:类与对象(二)

news2024/11/17 20:18:33

一.类中生成的默认成员函数详解

0.类的6个默认成员函数

编译器会给类生成六个默认成员函数,在类中即使我们什么都不做,也会自动生成。

默认成员函数:用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。

下面我们逐个来讲解这些函数。 

1.构造函数

1.1概念

对于以下Date类: 

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;
};

对于我们写的这个类来说,我们使用时需要用Init的公有方法给对象设置日期,但是如果我们每次都要使用Init方法给对象设置日期信息,未免有些过于繁琐,那么有没有办法能够在对象创建时就将信息设置进去呢?

构造函数即可完成这件事情。

构造函数是一个特殊的成员函数,它的名字和类名相同,在创建类类型对象时编译器会自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次

1.2特性

构造函数虽然叫构造函数,但其作用并不是开一个空间来创建对象而是初始化对象

其特征如下:

  • 函数名与类名相同
  • 无返回值
  • 对象实例化时编译器会自动调用相应的构造函数
  • 构造函数可以重载

下面我们来验证一下以上四个特性:

class Date
{
public:
	Date()//无返回值而且函数名与类名相同
	{
		_year = 2024;
		_month = 5;
		_day = 28;
	}
	Date(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 A;//调用无参构造
	A.Print();
	Date B(3, 4, 5);//调用三个参数的构造
	B.Print();
	return 0;
}

在上面这段代码中,通过打印,我们可以观察到一个调用了无参构造,一个调用了有参构造。

  • 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器将不再生成默认构造函数。

可以看到,我们在将构造函数屏蔽了之后,依旧是可以通过编译的,因此当我们不显式定义构造函数时,编译器会自动生成默认构造函数。 

现在我们执行下这段代码

我们发现了一个奇怪的现象,这里生成了随机值,那么默认构造函数做了什么事呢?

答案:C++将类型分为了内置类型和自定义类型,内置类型就是语言提供的类型,而自定义类型则是我们使用class/union/struct等关键字自己定义的类型。

而默认构造函数会对自定义类型成员调用它的默认构造函数。

我们可以用以下代码验证一下:

class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	int _year;
	int _month;
	int _day;
	Time _a;
};

我们在main函数中初始化了一个Date类型的对象,而Date类型的对象中声明了一个Time类型的对象,由于我们没有写Date类的默认构造函数,因此它会调用编译器自动生成的默认构造函数,这时默认的构造函数所作的事情就是去调用Date类中的自定义类型的构造函数。而Time类的构函数中打印了Time(),因此这段程序的最终输出结果为上图所示。

注意点:在C++11版本中,为我们无法对内置类型生成默认构造的问题打了一个补丁,我们可以在声明时给一个缺省值。

如下图所示

无参的构造函数和全缺省的构造函数都被称为默认构造函数,并且默认构造函数只能有一个。

主要注意的是:无参的构造函数、全缺省的构造函数、编译器生成的构造函数只能有一个,否则会有调用歧义。

譬如下图代码,编译器则会不知道调用的是哪个函数。

总结:不用传递参数就可以调用的构造函数就是默认构造函数。 

2.析构函数

2.1概念

刚刚我们学习了构造函数,现在我们已经知道一个对象是怎么来的了,那么它是怎么没的呢?这就需要析构函数来大显神威了!

析构函数:与构造函数功能相反,析构函数不是完成对对象的销毁,局部对象的销毁工作(生命周期)是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

2.2特性

析构函数是特殊的成员函数,其特征如下:

  • 析构函数名是在类名前加上~
  • 无参数无返回值类型
  • 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  • 析构函数不能重载
  • 对象生命周期结束时,C++编译系统自动调用析构函数。

下面我们还是来使用一下它

typedef int DataType;
class STack
{
public:
	STack(size_t capacity = 3)
	{
		_a = (DataType*)malloc(sizeof(DataType) * capacity);
		if (!_a)
		{
			perror("malloc fail!");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		_a[_size] = data;
		_size++;
	}
	~STack()
	{
		if (_a)
		{
			cout << "我析构啦!" << endl;
			free(_a);
			_a = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _a;
	int _capacity;
	int _size;
};
int main()
{
	STack s;
	s.Push(1);
}

这里我们可以发现,当s的生命周期要结束时,编译器自动调用了析构函数。

  • 与构造函数类似,编译器生成的析构函数也只会调用自定义类型的析构函数
class Time
{
public:
~Time()
{
cout << "我析构啦!" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本类型(内置类型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d;
return 0;
}

 这里不再画序号帮助大家理解过程,而是通过文字帮助大家深入理解原理
 在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数?
原因:main方法中创建了Date对象d,而d中包含4个成员变量,其中_year, _month,
_day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。但是,main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁。main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数。
注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数
 

  • 如果类中没有在堆上申请资源,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。。

3.拷贝构造函数

3.1概念

在现实生活中,我们在超市买小面包,可以认为同一种类型的两袋小面包是一样的。

那么,有没有一样的对象呢?我们能否创建一个跟已有对象一样的对象呢?

这就引入了我们的拷贝构造函数。

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

3.2特性

  • 拷贝构造函数是构造函数的一个重载形式。
  • 拷贝构造函数的参数只有一个而且必须是类类型对象的引用,使用传值方式编译器会报错,因为会引发无穷递归调用。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// Date(const Date d) // 错误写法:编译报错,会引发无穷递归
Date(const Date& d) // 正确写法。
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1);
return 0;
}

  • 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造对象按照内存存储字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。(和memcpy的拷贝模式一样)。

对于我们的Date类来说,值拷贝就已经够用了,但是别的类呢?就譬如说我们的栈

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

我们在运行这段代码时会发现它崩溃了,这是为什么呢?我们的s1对象中使用malloc动态开辟了一块内存,而我们是字节序拷贝的,因此我们的s2的array数组也指向了这块内存,而在程序退出时,s2和s1都要销毁,此时s2先销毁,s1再销毁(原因是栈区先进后出),s2已经将malloc的那块内存释放掉了,s1再去释放就会崩溃了。

 因此,我们可以得到如此一个结论:类中如果没有涉及到资源的申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数必须要写。

3.3拷贝构造的使用方法

我们的拷贝构造有两种写法,分别如下:

Stack s2(s1);//新创一个对象s2,并将s1拷贝给s2。
Stack s2 = s1;//这样也是可以完成拷贝的。

4.运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

注意点:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
  • 藏的this
  • .*   ::   sizeof   ?:     .    注意以上5个运算符不能重载。

现在我们来重载一个运算符:

//类内-->成员函数
bool operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
//类外-->全局函数
bool operator==(const Date& d1, const Date& d2)
{
return d1._year == d2._year
&& d1._month == d2._month
&& d1._day == d2._day;
}

在这里提一句题外话,我们在写代码的途中,能用引用返回或者引用传值时就尽量用引用,因为它它的效率会比较高。至于能否用引用返回,这需要我们关注他们的生命周期。 

5.赋值运算符重载

  • 参数类型:const Date&, 传递引用可以提高传参效率
  • 返回值类型 Date&,返回引用可以提高返回的效率,有返回值的目的是为了方便连续赋值
  • 检测是否自己给自己赋值
  • 返回*this,以满足连续赋值。
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
    //成员函数-->第一个参数是隐藏的this指针
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
//全局函数-->没有隐式的this,需要传递两个参数。
Date& operator=(const Date& Mythis,const Date& d)
{
	if (Mythis != &d)
	{
		Mythis._year = d._year;
		Mythis._month = d._month;
		Mythis._day = d._day;
	}
	return *Mythis;
}

按理来说,上述的代码是可以跑的过去的,但是实际上会产生编译错误。

为什么赋值运算符必须是成员函数呢?

这是因为赋值运算符如果不显式实现,编译器会生成一个默认的赋值运算符,此时用户再在类外自己实现一个全局的赋值运算符重载就会和编译器在类内生成的默认赋值运算符重载冲突。因此运算符重载只能是类的成员函数

如果我们不显式实现赋值运算符的话,编译器生成的赋值运算符是以值的方式逐字节拷贝

注意:

  • 1.内置类型成员变量是直接赋值的,而自定义类型的成员变量需要调用对应的类的赋值运算符重载完成赋值。
  • 需要深拷贝的类需要我们手写赋值运算符,浅拷贝即可解决需求的类用默认生成的即可。

关于运算符重载的知识这里不再阐述,博主会在后续写一篇日期类的实现讲运算符重载更加深入的讲解。 

6.const修饰函数

如果我们想要用const修饰类内某个成员函数的this指针,应该如何实现呢?

CPP将const修饰的成员函数称为const成员函数,而const修饰类成员函数,实际上修饰的是该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

譬如这段代码

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

int main()
{
	const Date d2(2022, 1, 13);
	d2.Print();//error
	return 0;
}

 由于我们传递的d2const的,但是在调用Print函数时,*this并没有加const修饰,这就造成了权限的放大,是不被允许的。因此我们应当将Print函数加上const修饰。

	void Print() const
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}

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

取地址(&)也是可以重载的,不过一般情况下不需要我们写重载函数。

class Date
{
public:
	Date* operator&()
	{
		return this;
	}
	const Date* operator&()const
	{
		return this;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

二.struct和class的对比

1struct

1.1struct的成员

在C++中,struct中不仅可以放数据类型,而且可以放函数。这个函数可以在类内定义,也可以在类外定义。

  • 类内定义
#include <iostream>
using namespace std;
struct kuzi
{
	int Add(int a, int b)
	{
		return a + b;
	}
};
int main()
{
	struct kuzi trousers;
	printf("%d", trousers.Add(3, 2));
	return 0;
}

  • 类外定义 

 1.1.2结构体的默认访问权限

在结构体中,为了兼容C语言,数据成员的默认访问权限为public,这也就代表着它们可以在结构体的外部直接进行访问。

如以下代码,我们可以直接给trousers这个对象的a和b进行赋值。

struct kuzi
{
	int a;
	int b;
};
int main()
{
	struct kuzi trousers;
	trousers.a = 3;
	trousers.b = 5;
	return 0;
}

 1.1.3访问权限控制

在C++11的标准中,引入了结构体成员的引用控制修饰符(public,privata,protect),我们可以显式的控制它的成员的访问权限。  

struct kuzi
{
	//默认是public
	int a;
	int b;
private:
	int c;
	int d;
};

1.2.class

在C++中,类(class)是一种重要的概念,可以创建用户定义的数据类型,其中可以包括数据成员成员函数。而且,C++中的类支持继承和多态等面向对象的概念,允许你通过基类创建派生类,实现代码的扩展和重用。剩下的知识点已经讲解过了,这里不再赘述。

1.3结构体Struct和类Class之间的区别以及各自使用场景

C++中的结构体(struct)和类(class)有一些相似之处,但也存在一些关键的区别。以下是结构体和类之间的主要区别:

1、默认访问权限:

结构体的成员默认访问权限是公共(public),因此结构体的成员在外部可以直接访问。
类的成员默认访问权限是私有(private),因此类的成员在外部不能直接访问,需要通过公共的成员函数来访问。
2、成员函数:

类可以包含成员函数,这些函数可以操作类的私有成员,并且可以实现类的行为和功能。
结构体也可以有成员函数,但是它们的主要目的是为了实现一些操作,而不是类似于类的行为。
3、继承:

类可以通过继承实现子类与父类之间的关系,可以使用公共、保护或私有继承来控制成员的访问权限。
结构体也可以继承,但由于其成员默认是公共的,继承可能导致访问权限问题,当然我们也可以控制其访问权限,让其可以继承。
4、构造函数和析构函数:

拥有构造函数和析构函数,用于对象的初始化和清理。
结构体也可以有构造函数和析构函数(但不会默认生成),但是它们的使用场景通常是比较简单的数据封装。
5、默认成员访问标签(Access Labels):

在类和结构体中,可以使用访问标签(public、private、protected)来指定成员的访问权限。

6、 使用场景:

结构体的使用场景:

用于存储一组相关的数据,但没有复杂的操作和逻辑。
类的使用场景:

当你需要封装数据并附加操作和行为时,类更适合,因为它可以将数据和操作封装在一起。
在实现更复杂的数据结构,如树、图等,使用类也更加合适。
总结:
  虽然结构体和类在某些方面很相似,但它们的默认行为、访问权限、使用场景以及是否支持面向对象编程的特性(如继承、多态等)都有一些差异。在选择使用结构体还是类时,需要考虑你的代码的需求和设计目标。但是,结构体可以做的事类都可以干,结构体不可以干的事类也都可以干!

码字不易,如果你觉得博主写的不错,给个三联关注评论把!!!

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

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

相关文章

蓝桥杯物联网竞赛_STM32L071_18_长短按键检测

长短按键的检测是国赛题里面遇到的&#xff0c;省赛没出过有两种实方法 定时器配置&#xff1a; 定时器的话要比delay准确&#xff0c;其中tim7定时器的准度最高 定时器预分配配置32 - 1&#xff0c;计数周期是10000 - 1这样做那么32MHZ/32也就是一秒钟记录10^6的数&#xf…

数组的定义、顺序存储及特殊矩阵的存储

目录 一、数组的定义 1.1概念 1.2抽象数据类型定义 二、数组的顺序存储 2.1一维数组元素的存储位置 2.2二维数组元素的存储位置 2.3三维数组元素的存储位置 三、特殊矩阵的压缩存储 3.1相关概念 3.2对称矩阵 3.3三角矩阵 3.4对角矩阵&#xff08;带状矩阵&#xff0…

Java 数据类型:学习和区分Java的基本数据类型(如int、float、boolean等)和引用数据类型(如数组、类等)

Java数据类型 Java是一种强类型语言&#xff0c;所有变量在使用前都必须声明其类型。Java的数据类型分为基本数据类型&#xff08;Primitive Data Types&#xff09;和引用数据类型&#xff08;Reference Data Types&#xff09;。了解并区分这两类数据类型是学习Java编程的重…

PC网游、页游、手游、端游各类游戏收集整理大集合-90%以上游戏带视频架设教程

本游戏资源提供给大家学习及参考研究借鉴美工之用&#xff0c;请勿用于商业和非法用途&#xff0c;无任何技术支持&#xff01; 干货列表

如何将RK R75键盘的右Alt键改为Ctrl键

打开注册表地址栏中输出 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout右键新建二进制值&#xff0c;名称设为ScanCode Map按下图输入数值

什么是知识中台?为什么企业需要知识中台?

如今市面上的企业数不胜数&#xff0c;企业的任何一个小细节都会产生很大的影响。近几年来一直很热门的知识中台备受企业关注。关于如何高效地管理、整合和运用知识&#xff0c;成为了每一家企业都在重点关注的问题。而知识中台&#xff0c;就是为了解决这一问题而诞生的一个全…

软件功能测试的类型和流程分享

在现代社会&#xff0c;软件已经成为人们生活中不可或缺的一部分&#xff0c;而在软件的开发过程中&#xff0c;功能测试是不可或缺的环节。软件功能测试指的是对软件系统的功能进行检查和验证&#xff0c;以确保软件在各种情况下能够正常运行&#xff0c;并且能够按照用户需求…

【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)

&#x1f50d;目的 以这样一种方式处理昂贵的远程服务调用&#xff0c;即单个服务/组件的故障不会导致整个应用程序宕机&#xff0c;我们可以尽快重新连接到服务 &#x1f50d;解释 真实世界例子 想象一个 Web 应用程序&#xff0c;它同时具有用于获取数据的本地文件/图像和远程…

车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文

系列文章目录 车载网络测试实操源码_使用CAPL脚本解析hex、S19、vbf文件 车载网络测试实操源码_使用CAPL脚本对CAN报文的Counter和CRC进行实时监控 车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文 车载网络测试实操源码_使用CAPL脚本实现安全…

如何在Spring Boot中整合PageHelper实现分页功能

1.前言 在开发web应用程序时&#xff0c;经常会遇到需要对数据库中的数据进行分页查询的情况。为了简化分页查询的实现过程&#xff0c;我们可以利用PageHelper这个优秀的分页插件来实现分页功能。本文将介绍如何在Spring Boot项目中整合PageHelper&#xff0c;并演示如何使用它…

docker和containerd的区别

docker和containerd的区别 1、容器运行时 1.1 容器运行时概念 容器运行时&#xff08;Container Runtime&#xff09;是一种负责在操作系统层面创建和管理容器的软件工具或组件。它是容器化技术的核心组件之一&#xff0c;用于在容器内部运行应用程序&#xff0c;并提供隔离…

零基础,想做一名网络安全工程师,该怎么学习?

​ 相比IT类的其它岗位&#xff0c;网络工程师的学习方向是比较明亮的。想要成为网络工程师&#xff0c;华为认证就是最好的学习方法。而网络工程师的从零开始学习就是从华为认证的初级开始学起&#xff0c;也就是HCIA&#xff0c;也就是从最基本的什么是IP地址、什么是交换机这…

IDEA2024创建maven项目

1、new->project 2、创建后展示 3、生成resources文件夹 4、测试--编写一个hello文件

STM32——定时器

一、简介 *定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断 *16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时 *不仅具备基本的定时中断功能&#xff0c;而且还包含内外时钟源选择、输入…

Autosar Dcm配置-特定NRC实现方式-基于ETAS软件

文章目录 前言工具配置代码编写总结 前言 项目开发过程中&#xff0c;诊断服务一般客户需求或系统需求都会有特定NRC(一般为NRC22-条件不满足)&#xff0c;也就会有特定的条件&#xff0c;需要手动加代码实现。本文介绍ETAS工具中配置的接口及简单实现。 工具配置 对于每一个…

Redis常用命令——Hash篇

前面我们讲述了String的相关操作命令。本篇文章主要讲解Redis中数据结构Hash的相关操作命令。希望会对你有所帮助。 目录 一、Hash哈希 二、命令 HSET HGET HEXISTS HDEL HKEYS HVALS HGETALL HMGET HLEN HSETNX HINCRBY 和 HINCRBYFLOAT 三、小结 &#x1f64b;‍♂️ 作者&a…

css 渐变色边框

效果图&#xff1a; 代码&#xff1a; <style>:root{--br-radius: 12px;}.list{position: relative;}.list_tle{margin-top: 15px;margin-bottom: 5px;}.item{position: relative;display: inline-flex;} .br1 {padding: 10px 16px;clip-path: inset(0 round 6px);borde…

【C++】挑战与机遇并存的编程语言—前序

C&#xff1a;挑战与机遇并存的编程语言 一、C的难点与挑战二、C的学习方法与策略三、C的实战应用与代码实例 在当今科技飞速发展的时代&#xff0c;编程语言的选择对于每一个开发者来说都至关重要。C&#xff0c;作为一种历史悠久且功能强大的编程语言&#xff0c;一直在软件开…

el-date-picker限制时间选择,不能选择当前日期之后时间

要求&#xff1a;时间选择不能超过当前日期之后的 效果&#xff1a; 结构代码&#xff1a;&#xff1a; <el-form-item label"时间&#xff1a;"><el-date-pickerv-model"time"type"datetimerange"range-separator"至"start…

【算法】重建二叉树并进行后序遍历的Java实现

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…