C++ ------ 类和对象的深究

news2024/10/5 17:22:13

文章目录

  • 构造函数
    • 初始化列表
      • 概念
      • 特性
    • explicit关键字
  • static成员
    • 概念
    • 特点
  • 友元
    • 友元函数
    • 友元类
      • 概念
      • 特性
  • 内部类
    • 概念
    • 特点
  • 匿名对象
  • 拷贝对象时的一些编译器优化

构造函数

我们来看下面的代码:

#include <iostream>
using namespace std;

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

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

上面的代码虽然在每次实例化对象是都给每个成员变量设定了初始值,但这并不是初始化,构造函数体内的语句只能将其称为赋初值,并不是初始化,因为初始化成员变量只能初始化一次,而构造函数可以给成员变量多次赋值,所以怎么样才能对成员变量初始化呢,这里引出了初始化列表的概念

初始化列表

概念

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d(1, 1, 1);
	return 0;
}

在这里插入图片描述

特性

  • 每个成员变量在初始化类表中最多只能出现一次(初始化只能初始化一次)
  • 类中包含以下成员,必须放在初始化列表位置进行初始化
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)
class A
{
public:
	A(int a)
		:_a(a)
	{
		std::cout << "A(int a)" << std::endl;
	}
private:
	int _a;
};


class B
{
	B(int a, int& b)
		:_b(a)
		,_c(b)
		,obj(2)
	{
		std::cout << "B(int a, int& b)" << std::endl;
	}
private:
	//const和引用的特点是必须在声明时初始化
	const int _b;
	int& _c;
	//自定义类型
	A obj;
};

这里需要注意:如果这里A对象为默认的无参构造函数,则B的初始化列表就不能对obj进行初始化,obj对象只能由编译器调用A类的无参的默认构造函数来创建对象。如果想要在B的初始化列表初始化我们必须把A的默认构造写成缺省构造。如以下代码:

class A
{
public:
	A(int a = 1)
	{
		std::cout << "A(int a = 1)" << std::endl;
	}
private:
	int _a;
};

class B
{
public:
	B(int a, int& b)
		:_b(a)
		, _c(b)
		,obj(10)
	{
		std::cout << "B(int a, int& b)" << std::endl;
	}
private:
	//const和引用的特点是必须在声明时初始化
	const int _b;
	int& _c;
	//自定义类型
	A obj;
};


int main()
{
	int n = 10;
	B b1(1,n);
}

当然也可以让编译器自动调用该缺省默认函数

class A
{
public:
	A(int a = 1)
		:_a(a)
	{
		std::cout << "A(int a = 1)" << std::endl;
	}
private:
	int _a;
};

class B
{
public:
	B(int a, int& b)
		:_b(a)
		, _c(b)
	{
		std::cout << "B(int a, int& b)" << std::endl;
	}
private:
	//const和引用的特点是必须在声明时初始化
	const int _b;
	int& _c;
	//自定义类型
	A obj;
};


int main()
{
	int n = 10;
	B b1(1,n);
}

在这里插入图片描述

我们书写构造函数时尽量写成初始化列表的构造函数,但是初始化列表代替不了函数体内赋值,比如:

template <typename T1>
//模板类
class Stack
{
public:
	Stack(int capacity = 3)
		:_array((T1*)malloc(sizeof(T1)*capacity))
		,_capacity(capacity)
		,_top(0)
	{
		//对malloc进行判空
		if (NULL == _array)
		{
			ferror("malloc failed!");
			return;
		}
	}
	void CheckCapacity()
	{
		if (_top == _capacity)
		{
			T1* temp = (T1*)realloc(_array, sizeof(T1) * _capacity * 2);
			if (NULL == temp)
			{
				perror("realloc failed!\n");
				return;
			}
			_array = temp;
			_capacity *= 2;
			cout << "扩容成功!" << endl;
		}
	}
	void PushStack(T1 x)
	{
		CheckCapacity();
		_array[_top] = x;
		_top++;
	}
	void PopStack()
	{
		if (_top > 0)
		{
			_top--;
		}
		else
		{
			cout << "退栈失败,栈已为空!" << endl;
			return;
		}
	}
	bool EmptyStack()
	{
		return _top == 0;
	}

	T1 StackTop()
	{
		return _array[_top - 1];
	}

	~Stack()
	{
		delete[] _array;
		_array = NULL;
		_capacity = _top = 0;
	}
private:
	T1* _array;
	int _capacity;
	int _top;
//我们还可以在外面控制capacity比如用两个栈实现一个队列
class MyQueue
{
public:
	MyQueue()
	{
		
	}
	MyQueue(int capacity)
		:pushst(capacity)
		,popst(capacity)
	{}
private:
	Stack<int> pushst;
	Stack<int> popst;
};


int main()
{
	MyQueue q1(10);
}
};

这里还有一个坑,声明顺序和定义的顺序保持一致。 我们来看一下下面代码:

class A
{
public:
	A(int a)
		:_a1(a)   //_a1 = 1
		,_a2(_a1) //_a2 = 随机值
	{}

	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};

int main()
{
	A aa(1);
	aa.Print();
	return 0;
}

在这里插入图片描述
所以我们需要在初始化列表中初始的顺序要和声明的顺序相同。

explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

class Date
{
	//友元函数
	friend ostream& operator<<(ostream& cout, const Date& d);
public:
	 Date(int year)
		:_year(year)
	{}

	/*Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}*/
	//赋值运算符重载
	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;
};
ostream& operator<<(ostream& cout, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
	return cout;
}

int main()
{
	Date d1(2022);
	//2023利用构造函数生成一个Date类型的对象然后再利用赋值运算符重载函数赋值给d1
	//但是编译器会默认优化为一个构造
	d1 = 2023;
	cout << d1 << endl;
}

单参构造函数,没有使用explicit修饰,具有类型转换的作用。
explicit 修饰构造函数,禁止类型转换
缺省构造函数,虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转换作用。explicit修饰构造函数,禁止类型转换。
以上main函数里的代码是:利用一个整型变量给日期类型对象赋值,实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值。

class Date
{
	//友元函数
	friend ostream& operator<<(ostream& cout, const Date& d);
public:
	explicit Date(int year)
		:_year(year)
	{}

	/*Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}*/
	//赋值运算符重载
	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;
};
ostream& operator<<(ostream& cout, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
	return cout;
}

int main()
{
	Date d1(2022);
	//2023利用构造函数生成一个Date类型的对象然后再利用赋值运算符重载函数赋值给d1
	//但是编译器会默认优化为一个构造
	d1 = 2023;
	cout << d1 << endl;
}

在这里插入图片描述

结论:用explicit修饰构造函数,将会禁止构造函数的隐式转换。

static成员

概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量,用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
我们来看下面的代码:
实现一个类,计算程序中创建出了多少个类对象。

class A
{
public:
	A()
	{
		scount++;
	}
	A(const A& a)
	{
		scount++;
	}
	~A()
	{
		scount--;
	}
	static int GetScount()
	{
		return scount;
	}
private:
	static int scount;
};

int A::scount = 0;

A a;
int main()
{
	cout << __LINE__ << " " << A::GetScount() << endl;

	A b = a;
	cout << __LINE__ << " " << A::GetScount() << endl;
}

在这里插入图片描述

特点

  • 静态成员为所有类对象所共享,不属于某个具体的对象,存放再静态区。
  • 静态成员变量必须在类外定义,定义是不添加static关键字,类中只是声明
  • 类静态成员即可用类名 :: 静态成员或者对象.静态成员来访问。
  • 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  • 静态成员也是类的成员,受public、protected、private访问限定符的限制。
    需要注意:静态成员函数可以调用静态成员函数,不能调用非静态成员函数,非静态成员函数可以调用静态成员函数。

友元

友元最基本的作用是让类外的函数可以访问类内的私有成员。但是它破化了封装性,所以我们需要谨慎使用友元,友元可以分为友元函数和友元类。
我们需要实现流插入和流提取的运算符重载,但是它们不能被实现为类成员函数,因为实现成类成员函数,会有this指针抢占第一个运算形参的位置,这就会造成冲突,this指针默认是第一个参数了。但是实际使用中cout需要是第一个形参对象才能正常使用。所以要将流插入和流提取运算符重载为全局函数。但这会导致类外的函数不能访问类内的成员,此时就需要友元来解决。看下面的代码我们实现了这两个运算符的重载。

友元函数

class Date
{
	//友元函数
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900,int month = 1,int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	/*Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}*/
	//赋值运算符重载
	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;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day << endl;
	return cout;
}
istream& operator>>(istream& _cin,Date& d) 
{
	_cin >> d._year;
	_cin >> d._month;
	_cin >> d._day;
	return cin;
}

int main()
{
	Date d1;
	//2023利用构造函数生成一个Date类型的对象然后再利用赋值运算符重载函数赋值给d1
	//但是编译器会默认优化为一个构造
	cin >> d1;
	cout << d1 << endl;
}

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

友元类

class Time
{
	//date类是Time的友元。
	//友元只能是单向的
	//在该例子中不能访问Date类中的成员而Date类可以访问Time类中的成员
	friend class Date;
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		:_hour(hour)
		,_minute(minute)
		,_second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
	//友元函数
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	/*Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}*/
	//设定日期类的时间
	void SetTimeofDate(int hour, int minute, int second)
	{
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
	//赋值运算符重载
	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;
	Time _t;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day << endl;
	return cout;
}
istream& operator>>(istream& _cin, Date& d)
{
	_cin >> d._year;
	_cin >> d._month;
	_cin >> d._day;
	return cin;
}

int main()
{
	Date d1;
	//2023利用构造函数生成一个Date类型的对象然后再利用赋值运算符重载函数赋值给d1
	//但是编译器会默认优化为一个构造
	cin >> d1;
	cout << d1 << endl;
}

概念

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

特性

友元关系是单向的,不具有交换性。

  • 比如上述的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量是不可以的,所以具有单项行,谁是谁的友元类,谁就能访问另一个类的私有成员。

友元关系不能传递

  • 如果C是B的友元,B是A的友元,则不能说明C是A的友元。

友元关系不能被继承。

内部类

class Date
{
	//友元函数
public:
	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	//Time天生就是Date类的友元。此类不占任何空间,也就是说sizeof(Date) == Date的大小
	//它受访问修饰限定符的限制,可以写成保护,私有,公共。
	class Time
	{
		friend class Date;
	public:
		Time(int hour = 0, int minute = 0, int second = 0)
			:_hour(hour)
			,_minute(minute)
			,_second(second)
		{}
	private:
		int _hour;
		int _minute;
		int _second;
		//不计算静态成员的大小
		static int k;
	};

	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;
};
int Date::Time::k = 0;
int main()
{
	Date d1;
	Date::Time t;
	//但是不能这样写
	//Time t1;
}

概念

如果一个类定义在另一个类的内部,这个类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象来访问外部类中的所有成员,但是外部类不是内部类的友元。

特点

  • 内部类可以定义在外部类的public、protected、private都是可以的。
  • 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象 /类名。
class Date
{
	//友元函数
public:
	Date(int year = 1900, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	//Time天生就是Date类的友元。此类不占任何空间,也就是说sizeof(Date) == Date的大小
	//它受访问修饰限定符的限制,可以写成保护,私有,公共。
	class Time
	{
		friend class Date;
	public:
		Time(int hour = 0, int minute = 0, int second = 0)
			:_hour(hour)
			,_minute(minute)
			,_second(second)
		{}
		void foo(const Date& d)
		{
			cout << k << endl;   //ok
			cout << d.i << endl; //ok
		}
	private:
		int _hour;
		int _minute;
		int _second;
		//不计算静态成员的大小
		static int k;
	};

	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;
	static int i;
};
int Date::Time::k = 0;
int Date::i = 0;
int main()
{
	Date d1;
	Date::Time t;
	t.foo(d1);
	//但是不能这样写
	//Time t1;
}

在这里插入图片描述

  • sizeof(外部类) = 外部类,和内部类没有任何关系。

在这里插入图片描述

匿名对象

匿名对象的特点是不用起名字,我们看下面的代码:

class A
{
public:
	A(int a = 1)
		:_a(a)
	{
		cout << "A(int a = 1)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}

private:
	int _a;
};


int main()
{
	//匿名对象的特点是不用取名字,但是它们的生命周期只有这一行,我们证明这一点,它会在这一行结束后调用析构函数
	A();
}

在这里插入图片描述
还需要注意,引用不能引用匿名对象,但是加上const以后就可以了,这是因为匿名对象就像临时变量一样具有常性,前面加上const后就可以引用了,权限可以缩小和平移不能放大。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

拷贝对象时的一些编译器优化

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa)
		:_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
void f1(A aa)
{}
A f2()
{
	A aa;
	return aa;
}
int main()
{
	// 传值传参
	A aa1;
	f1(aa1);
	cout << endl;
	// 传值返回
	f2();
	cout << endl;
	// 隐式类型,连续构造+拷贝构造->优化为直接构造
	f1(1);
	// 一个表达式中,连续构造+拷贝构造->优化为一个构造
	f1(A(2));
	cout << endl;
	// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造
	A aa2 = f2();
	cout << endl;
	// 一个表达式中,连续拷贝构造+赋值重载->无法优化
	aa1 = f2();
	cout << endl;
	return 0;
}

在这里插入图片描述
我们下一篇再见!

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

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

相关文章

三周目创作纪念日

机缘收获日常成就憧憬 机缘 最初成为创作者的初心 实战项目中的经验分享日常学习过程中的记录通过文章进行技术交流 收获 在创作的过程中都有哪些收获 获得了很多粉丝的关注获得了很多正向的反馈&#xff0c;如赞、评论、阅读量等认识了很多志同道合的领域同行 日常 当前创…

【零基础学Rust | 基础系列 | Hello, Rust】编写并运行第一个Rust程序

文章目录 前言一&#xff0c;创建项目二&#xff0c;两种编译方式1. 使用rustc编译器编译2. 使用Cargo编译 总结 前言 在开始学习任何一门新的编程语言时&#xff0c;都会从编写一个简单的 “Hello, World!” 程序开始。在这一章节中&#xff0c;将会介绍如何在Rust中编写并运…

CSS学习记录(基础笔记)

CSS简介: CSS 指的是层叠样式表* (Cascading Style Sheets)&#xff0c;主要用于设置HTML页面的文字内容&#xff08;字体、大小、对齐方式&#xff09;&#xff0c;图片的外形&#xff08;边框&#xff09; CSS 描述了如何在屏幕、纸张或其他媒体上显示 HTML 元素 CSS 节省…

JVM面试题--实践

目录 JVM 调优的参数可以在哪里设置参数值 war包部署在tomcat中设置 jar包部署在启动参数设置 JVM 调优的参数都有哪些&#xff1f; 设置堆空间大小 虚拟机栈的设置 年轻代中Eden区和两个Survivor区的大小比例 年轻代晋升老年代阈值 设置垃圾回收收集器 JVM 调优的工…

《高质量数字化转型产品及服务全景图(2023上半年度)》希尔贝壳成功入选

2023年7月27日&#xff0c;由中国信息通信研究院泰尔终端实验室主办的2023数字生态发展大会暨中国信通院“铸基计划”年中会议在北京成功召开。在本次会上&#xff0c;中国信通院重磅发布《高质量数字化转型产品及服务全景图&#xff08;2023上半年&#xff09;》&#xff0c;希…

MySQL索引1——基本概念与索引结构(B树、R树、Hash等)

目录 索引(INDEX)基本概念 索引结构分类 BTree树索引结构 Hash索引结构 Full-Text索引 R-Tree索引 索引(INDEX)基本概念 什么是索引 索引是帮助MySQL高效获取数据的有序数据结构 为数据库表中的某些列创建索引&#xff0c;就是对数据库表中某些列的值通过不同的数据结…

MVC配置原理

如果你想保存springboot的mvc配置并且还想自己添加自己的配置就用这个。 视图解析器原理&#xff0c;它会从IOC容器里获取配置好视图解析器的配置类里的视图解析器集合&#xff0c; 然后遍历集合&#xff0c;生成一个一个的视图对象&#xff0c;放入候选 视图里&#xff0c;…

【华秋干货铺】PCB布线技巧升级:高速信号篇

如下表所示&#xff0c;接口信号能工作在8Gbps及以上速率&#xff0c;由于速率很高&#xff0c;PCB布线设计要求会更严格&#xff0c;在前几篇关于PCB布线内容的基础上&#xff0c;还需要根据本篇内容的要求来进行PCB布线设计。 高速信号布线时尽量少打孔换层&#xff0c;换层优…

word转pdf两种方式(免费+收费)

一、免费方式 优点&#xff1a;1、免费&#xff1b;2、在众多免费中挑选出的转换效果相对较好&#xff0c;并且不用像openOffice那样安装服务 缺点&#xff1a;1、对字体支持没有很好&#xff0c;需要安装字体库或者使用宋体&#xff08;对宋体支持很好&#xff09;2、对于使…

使用vuex让购物车联动

// 1.vuex点击加减触发函数提交仓库把我们请求的数据存到仓库 2.在仓库定义这个函数和对象 把我们存进去的数据存起来 // 3。在我们需要的页面拿出数据&#xff0c;然后循环就可以 // 4.当我们点击加号就触发函数然后在vuex对这个数据进行处理 // 5.对我们点进来的数据进行一个…

使用自适应去噪在线顺序极限学习机预测飞机发动机剩余使用寿命(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【零基础学Rust | 基础系列 | Rust初相识】Rust简介与环境配置

教程目录 前言一&#xff0c;Rust简介1&#xff0c;Rust的历史2&#xff0c;Rust的特性3&#xff0c;为什么选择Rust4&#xff0c;Rust可以做什么 二&#xff0c; Rust环境配置1&#xff0c;windows11安装2&#xff0c;Linux安装 三&#xff0c;安装IDE 前言 Rust是一种系统编…

无头单链表,有完整测试程序

&#x1f35f;无头单链表 &#x1f47b;无头单链表的所有结点都存储有效信息 &#x1f47b;无头单链表相对带头单链表&#xff0c;在有些涉及更改头节点的函数上需要传二级指针 &#x1f35f;头文件list.h #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #includ…

不能乱点链接之获取cookie

这里是浏览器存储的某个网址的cookie 然后点击了链接就把参数获取到 因为document.cookie 会直接获取到浏览器cookie 所以为了拦截 存cookie的时候要设置&#xff1a; 设置httpOnly 只要http协议能够读取和携带 再document.cookie 就为空了 原文链接&#xff1a; 尚硅谷课程…

后端整理(MySql)

1 事务 1.1 事务ACID原则 原子性&#xff08;Atomicity&#xff09; 事务的原子性指的是事务的操作&#xff0c;要么全部成功&#xff0c;要么全部失败回滚 一致性&#xff08;Consistency&#xff09; 事务的一致性是指事务必须使数据库从一个一致状态转变成另一个一致性…

SolidUI社区-从开源社区角度思考苹果下架多款ChatGPT应用

文章目录 背景下架背景下架原因趋势SolidUI社区的未来规划结语如果成为贡献者 背景 随着文本生成图像的语言模型兴起&#xff0c;SolidUI想帮人们快速构建可视化工具&#xff0c;可视化内容包括2D,3D,3D场景&#xff0c;从而快速构三维数据演示场景。SolidUI 是一个创新的项目…

Typescript中的元组与数组的区别

Typescript中的元组与数组的区别 元组可以应用在经纬度这样明确固定长度和类型的场景下 //元组和数组类似&#xff0c;但是类型注解时会不一样//元组赋值的类型、位置、个数需要和定义的类型、位置、个数完全一致&#xff0c;不然会报错。 // 数组 某个位置的值可以是注解中的…

小白到运维工程师自学之路 第六十五集 (docker-compose)

一、概述 Docker Compose 的前身是 Fig&#xff0c;它是一个定义及运行多个 Docker 容器的工具。可以使用YAML文件来配置应用程序的服务。然后&#xff0c;使用单个命令&#xff0c;您可以创建并启动配置中的所有服务。Docker Compose 会通过解析容器间的依赖关系&#xff08;…

纷享销客携30+企业家朋友走进国产燃气轮机领军企业——新奥动力

7月26日下午&#xff0c;【数字中国-高效增长】名城优企游学系列活动之走进新奥动力成功举办&#xff01;新奥动力是国产燃气轮机领军企业&#xff0c;成立于2013年&#xff0c;致力于成为国际领先的微、小型燃气轮机制造商&#xff0c;其多项技术、产品填补国内空白。2022年新…

算法通关村—迭代实现二叉树的前序,中序,后序遍历

1. 前序中序后序递归写法 前序 public void preorder(TreeNode root, List<Integer> res) {if (root null) {return;}res.add(root.val);preorder(root.left, res);preorder(root.right, res);}后序 public static void postOrderRecur(TreeNode head) {if (head nu…