C++入门(2)-类与对象

news2025/8/2 21:55:58

类与对象

  • 初步认识类与对象
    • 一、面向过程与面向对象的区别
    • 二、类与结构体
    • 三、类的定义
    • 四、类的实例化
    • 五、类对象
    • 六、this指针
    • 七、构造函数
    • 八、析构函数
    • 九、拷贝构造函数
    • 十、运算符重载函数

初步认识类与对象

一、面向过程与面向对象的区别

C语言是面向过程进行编程,注重点在过程上,这个过程指的是解决问题的过程。C++是面向对象进行编程,注重点是对象,主要处理的是对象与对象间的关系。
举个例子来了解两者之间的区别,例如送外卖这件事情。
(1)面向过程
在这里插入图片描述

(2)面向对象

过程:外卖员到商家店铺,商家将外卖提供给外卖员。外卖员到客户指定点,将外卖送给客户,客户拿到外卖。

对象:外卖员、外卖、商家、客户
外卖员:前往商店拿外卖,将外卖送给客户
外卖:由商家提供,先给外卖员,最后给客户
商家:提供外卖给外卖员
客户:拿到外卖员送到的外卖
在面对对象中,客户不需要知道商家是如何制作外卖的,只需要拿到外卖员送到的外卖,并确认是否是自己点的外卖。每个对象只需要关注自己有关的事情,不需要了解整个国产的实现。
在这里插入图片描述

二、类与结构体

在C语言中结构体由struct关键字定义。C++中,类可以由class和struct关键字定义。C++是兼容C的,因此struct依旧可以作为结构体使用。
C++和C语言的struct的区别有哪些?C++的struct用法包含C的struct的用法,也就是说C++在C的struct基础上增加了一些东西,让其从结构体变成了类。
第一个点,C++中的struct不仅可以定义成员变量,还可以定义成员函数。
第二点,C++中struct声明的是类名(用C语言写结构体可以看做结构体名),在定义变量时,可以不用加struct,可以直接用类名做变量类型。
第三点,C++中struct中的成员函数和成员变量有公有和私有之分,公有就是可以在外部进行调用,私有只能在自己的类域中使用。(struct和class声明的类被{}圈定的范围就是类域)
class和struct的定义类的方法相同,都是由于定义类的关键字。在定义上的不同点是struct可以作为结构体使用,class不行。class定义的类成员和函数,在默认情况下都是私有的;struct定义的类成员和函数,在默认情况下都是公有的。
class和struct在继承和模板参数列表位置上也不一样,在后续会进行讲解。
public和private被称为访问限定符,public为公有权限,private为私有权限。

class Stack
{
public://公有
	void StackInit()
	{
		arr = nullptr;
		capacity = num = 0;
	}
private://私有
	DataType* arr;
	int capacity;
	int num;

};

int main()
{
	Stack st;
	st.StackInit();
	//st.capacity = 10;//错误操作,无法访问私有变量
	return 0;
}

在类中,类中的内容被称为类的成员;类中的函数被称为成员函数或者类的方法;类中的变量被称为成员变量或者成员属性

三、类的定义

类的定义大致分为两种,一种是类的成员声明和定义都放在类中,另一种是类的声明放在.h文件中,类的定义放在.cpp文件中。
1.声明和定义放类中:成员函数在类中定义可能会被编译器当成内联函数进行处理,也就是调用该函数时,不会开辟函数栈帧,而是会直接在调用处展开。

#include<stdio.h>
#include<string.h>

class Student
{
public:
	void Init(const char* name, int age, int score)
	{
		strcpy(_name, name);
		_age = age;
		_score = score;
	}
	void Print()
	{
		printf("%s %d %d", _name, _age, _score);
	}
private:
	char _name[20];
	int _age;
	int _score;
};

int main()
{
	Student s;
	s.Init("张三", 20, 88);
	s.Print();

	return 0;
}

2.声明放在.h文件、定义放在.cpp文件:在函数成员定义时,需要在函数成员名前面加作用域限定符,作用域为该类的类域。一般情况下,建议使用第二种方法。

//.h文件
class Student
{
public:
	void Init(const char* name, int age, int score);
	void Print();

private:
	char _name[20];
	int _age;
	int _score;
};
//.cpp文件
void Student::Init(const char* name, int age, int score)
{
	strcpy(_name, name);
	_age = age;
	_score = score;
}
void Student::Print()
{
	printf("%s %d %d", _name, _age, _score);
}

int main()
{
	Student s;
	s.Init("张三", 20, 88);
	s.Print();

	return 0;
}

为什么要加作用域限定符?因为成员函数都在类域中,出了类域是没法直接找到的。当函数前面加了作用域限定范围,就相当于可以直接找到该函数了,换句话讲,加完之后,相当于你在你家直接操控公司的电脑,那你在使用该电脑的时候,所有东西也只会在这个电脑里产生和销毁。

四、类的实例化

类的实例化就是用类类型去创建此类对象的过程。
在这里讲讲类和对象的关系,类相当于一个模板。比如你要创造一辆车,首先得有车的设计图纸。通过设计图纸才能高效的制造车,一张图纸就可以批量生成这种型号的车。类就是生产图纸,对象就是车,通过类可以批量创建对象。
类是不占内存的,而对象占内存。就像图纸上画的东西没有真正实现出来,只存在纸上,不额外占空间。生成出来的车子是真实存在的,占用物理空间。

五、类对象

类对象既然是类的实例化,那同样拥有成员函数和成员变量的,那成员如何计算其大小呢?需不需要计算成员函数的大小?成员函数的大小是不用计算的,因为成员函数并不在类对象中,而是在代码段中。为什么要这样子?如果每一个同类型的对象都需要拥有一个属于自己的函数,对象数量多,会造成大量的空间浪费,不如放在外面,供每个对象需要时使用。
按照上述说法,计算类对象大小只需要计算成员变量的大小,那是直接将成员变量大小相加就是类对象大小?不是的,这个和成员变量的存储方式有关。成员变量的内存存储方式和结构体的相同,不明白的可以看看前面的内存对齐。那按照结构体内存对齐的方式去计算大小就一定正确吗?不一样,有一种特殊情况,就是没有成员变量,但是这不能代表这个类对象大小是0,如果类对象大小是0,就表示这个对象根本没有开辟空间,没有地址如何表示这个对象?因此在没有成员变量的情况下,类对象大小为1,需要有一个地址来表示这个类对象。

六、this指针

#include<stdio.h>
#include<string.h>

class Student
{
public:
	void Init(const char* name, int age, int score)
	{
		strcpy(_name, name);
		_age = age;
		_score = score;
	}
	void Print()
	{
		printf("%s %d %d", _name, _age, _score);
	}
private:
	char _name[20];
	int _age;
	int _score;
};

int main()
{
	Student s1;
	Student s2;
	s1.Init("张三", 20, 88);
	s1.Print();
	s2.Init("李四", 21, 89);
	s2.Print();
	return 0;
}

为了方便讲解,使用第一种定义方法。在上面代码中,可以看到定义了两个类变量分别叫s1和s2,在调用Student类函数时,明明没有传入任何关于类变量的信息,那成员函数是如何区分并使用对应的成员变量?也就是说成员函数如何判断是使用s1的成员变量还是s2的?这其实是C++编译器给每个非静态成员函数都多加了一个指针参数,这个指针指向的就是调用这个函数的类变量。这个指针参数名字就是this,类型是类类型加上* const(如:Student * const this),这是为了防止this改变指向对象,出现误操作。
在成员函数中,使用成员变量_name在实现上其实是this->_name。这就是为什么成员函数可以随你的心意去实现相关操作,就是因为有些你看不到的东西,在默默守护你。那this存在哪里呢?this作为形参,一般都是存在于栈里,但是有些编译器上会将其放在寄存器中。

七、构造函数

构造函数是类中特殊的成员函数,其名字和类名相同,是在创建类对象时由编译器进行自动调用的函数。这也就是保证该函数只会在其生命周期内被调用一次。主要作用就是确保对象成员变量都有初始值。
那构造函数存在哪些特点呢?
1.函数名与类名相同
2.构建类对象时,会被编译器自动调用默认构造函数
3.没有返回值
4.构造函数可以函数重载,非默认构造函数需要自己调用

默认构造函数包括三种:(1)编译器自动生成的构造函数(2)自己定义的没有函数参数的构造函数(3)自己定义的全缺省构造函数

构造函数是默认存在的,也就是说,即使程序员没有在类中写构造函数,编码器会自己生成一个。
编译器自动生成的构造函数会具体实现哪些功能?为什么还要自己去定义构造函数?
先说明第一个问题,编译器自动生成的构造函数不会对内置类型变量进行初始化处理(不做处理),对应自定义类型变量会调用它的默认构造函数进行初始化处理。内置类型就是C++提供的数据类型,自定义类型就是自己定义的类型,比如上面用class和struct等等自己定义的类型。
第二个问题:第一个问题的结果说明了自动生成的构造函数不会对内置类型变量进行初始化,那么在存在内置类型的类中,往往需要对其进行初始化,所以需要自己定义构造函数。

#include<iostream>

class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)//构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		printf("%d-%d-%d\n", _year, _month, _day);
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	d1.Print();
	Date d2(2001,1,1);//构造函数传参方式比较特殊,直接在对象后面加()进行
	d2.Print();
	return 0;
}

在自己定义构造函数的时候,需要注意以下几点:(1)函数参数能用全缺省参数,尽量用全缺省,即使不行最好也是半缺省参数(最好用缺省参数)(2)构造函数不需要返回值(3)构造函数名字与类名相同
在C++11中对于自动生成的构造函数内置类型没有初始化打了个补丁,可以在成员变量定义时给默认值作为初始化。

八、析构函数

析构函数的作用与构造函数相反,构造函数是进行初始化,析构函数就是进行清理工作。
首先得知道析构函数什么时候会被调用?当对象生命周期结束需要销毁时,会调用析构函数先对其进行清理。那会清理什么?这和构造函数相似,析构函数对于内置类型是不做清理的,对自定义类型会调用其析构函数做清理。也就是说对于内置类型析构函数是不做任何操作的。如果说在一个管理栈的类,用编译器自动生成的析构函数,是会造成资源泄露的。举个例子,栈在使用时不可避免需要开辟空间,空间不进行释放会有什么后果应该都清楚(不清楚的可以看看前面的动态内存管理),因此在有申请资源时,最好写析构函数。
这里可能会有人觉得为什么析构函数和构造函数都没有对内置类型进行处理,怎么说呢,构造函数那里是存在问题,但是析构函数不对内置类型进行处理是考虑到有些情况下,不可以对申请的资源进行清理。比如说我申请了一块空间,但是这个空间我在外面还需要时候,不可以在对象销毁时进行清理。
析构函数的特点:
(1)函数名是"~"加上类名
(2)没有返回值且没有参数
(3)在对象生命周期结束编译器会自动调用析构函数
(4)析构函数没有函数重载,只能存在一个析构函数

#include<iostream>

class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	~Date()//析构函数
	{
		_year = _month = _day = 0;//没有清理资源可以不写,因为这些后面会被销毁掉
	}

	void Print()
	{
		printf("%d-%d-%d\n", _year, _month, _day);
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2001,1,1);
	d1.Print();
	return 0;
}

九、拷贝构造函数

拷贝构造函数只有一个函数参数,该参数类型为类的类型的引用,通常会加个const修饰。在通过已有对象创建新对象时,编译器会自动调用拷贝构造函数。
没有定义拷贝构造函数,编译器会自动生成一个。
拷贝构造函数特点:
(1)只有一个形参,并且形参类型必须为类类型的引用。
(2)是构造函数的重载形式
形参类型为什么必须是类类型的引用?如果只是用类的类型,本质上是传值调用,函数的传值本质是将该数值再拷贝一份临时变量传入函数中。这就会导致对象调用拷贝函数时,拷贝函数会对对象再次调用拷贝函数,不断循环往复陷入死循环。使用引用不会对对象进行拷贝,而是取了个别名,使用别名进行操作。通常加const是因为权限问题,const修饰的引用权限最小,其他数值都可以传入。
没有定义拷贝构造函数时,编译器会自动生成默认拷贝构造函数。默认拷贝构造函数对内置类型变量实现的是浅拷贝(或者值拷贝),就是对象的内存存储按字节序方式进行拷贝。也就是一个字节一个字节将对象拷到目标对象中。对自定义类型变量是通过调用它的拷贝构造函数进行拷贝。
那什么时候可以使用默认拷贝构造函数?在拷贝内容存在指针或者引用时,需要注意实际含义。举个例子,被拷贝的对象s1中有两个数值,一个为变量a,一个为指针pa,指针pa指向a变量。拷贝对象s2需要拷贝s1中的a和pa,那s2中的a值会与s1的相等,而s2中的pa却不是指向s2中的a,而s1中的a。这个情况和预期是有出入的,不是我们想要的结果,这时候需要自定义拷贝构造函数。

#include<iostream>

class Date
{
public:
	Date(int year = 0, 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;
	}
	~Date()
	{
		_year = _month = _day = 0;
	}

	void Print()
	{
		printf("%d-%d-%d\n", _year, _month, _day);
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2001, 1, 1);
	d1.Print();
	Date d2(d1);
	d2.Print();
	return 0;
}

十、运算符重载函数

为什么需要运算符重载函数?用运算符做个类比,我们在使用运算符的时候,可以实现变量之间的比较和加减乘除等等操作。但是运算符并不能对类对象以上的操作,类对象和类对象不能通过运算符直接进行运算,因此我们需要对运算符进行重载,使其可以对同类型的类对象进行运算。
在运算符重载中,赋值运算符重载函数在没有定义时,编译器会自动生成。如果类中没有进行资源管理,可以不用自己实现,否则需要自己定义赋值运算符重载函数。
运算符重载函数特点:
(1)“.”、“.*”、“::”、“?:”、"sizeof"这五个是不可以进行运算符重载的
(2)不可以改变内置类型的运算符含义
(3)返回类型 operator+“运算符”(形参)
(4)形参会比实际操作数少一个,因为第一个操作数会被作为隐藏的this指针进行传入

日期类的实现:

#include<iostream>
using std::ostream;
using std::cout;
using std::cin;
using std::endl;

class Date
{
	friend ostream& operator<<(ostream& out, const Date d);
public:
	int Judge_day(int year, int month);
	Date(int year = 0, int month = 1, int day = 1);
	
	bool operator>(Date d);
	bool operator==(Date d);
	bool operator<(Date d);
	bool operator>=(Date d);
	bool operator<=(Date d);
	bool operator!=(Date d);

	Date operator+=(int day);
	Date operator+(int day);
	Date operator-=(int day);
	Date operator-(int day);
	Date& operator=(const Date d);

	// 前置++
	Date & operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	int operator-(const Date& d);

	void Print() const;

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

ostream& operator<<(ostream& out, const Date d)
{
	out << d._year << "-" << d._month << "-" << d._day;
	return out;
}

int Date::Judge_day(int year, int month)
{
	int date[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	int day = date[month];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
	{
		day += 1;
	}
	return day;
}

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!(year >= 0
		&& month > 0 && month < 13
		&& day > 0 && day <= Judge_day(year, month)))
	{
		printf("日期错误: %d-%d-%d\n", year, month, day);
	}
}

bool Date::operator>(Date d)
{
	if (this->_year > d._year)
	{
		return true;
	}
	else if (this->_year == d._year && this->_month > d._month)
	{
		return true;
	}
	else if (this->_year == d._year && this->_month == d._month && this->_day > d._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}
bool Date::operator==(Date d)
{
	if (this->_year == d._year && this->_month == d._month && this->_day == d._day)
	{
	return true;
	}

	return false;
}

bool Date::operator<(Date d)
{
	return !(*this > d || *this == d);
}

bool Date::operator>=(Date d)
{
	return !(*this < d);
}
bool Date::operator<=(Date d)
{
	return !(*this > d);
}
bool Date::operator!=(Date d)
{
	return !(*this == d);
}

Date Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}
	int i = 0;
	day += this->_day;
	while (i = Judge_day(this->_year, this->_month), day > i)
	{
		day -= i;
		this->_month++;
		if (this->_month > 12)
		{
			this->_month = 1;
			this->_year++;
		}
	}
	this->_day = day;
	return *this;
}

Date Date::operator+(int day)
{
	if (day < 0)
	{
		return *this - (-day);
	}
	int i = 0;
	Date ret(*this);
	day += ret._day;
	while (i = Judge_day(ret._year, ret._month), day > i)
	{
		day -= i;
		ret._month++;
		if (ret._month > 12)
		{
			ret._month = 1;
			ret._year++;
		}
	}
	ret._day = day;
	return ret;
}

Date Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}
	day = this->_day - day;
	while (day <= 0)
	{
		this->_month--;
		if (this->_month < 1)
		{
			this->_month = 12;
			this->_year--;
		}
		day += Judge_day(this->_year, this->_month);
	}
	this->_day = day;
	return *this;
}

Date Date::operator-(int day)
{
	if (day < 0)
	{
		return *this + (-day);
	}
	Date ret(*this);
	day = ret._day - day;
	while (day <= 0)
	{
		ret._month--;
		if (ret._month < 1)
		{
			ret._month = 12;
			ret._year--;
		}
		day += Judge_day(ret._year, ret._month);
	}
	ret._day = day;
	return ret;
}


Date& Date::operator=(const Date d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
	return *this;
}

void Date::Print() const
{
	printf("%d-%d-%d\n", _year, _month, _day);
}

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date ret(*this);
	* this += 1;
	return ret;
}
// 后置--
Date Date::operator--(int)
{
	Date ret(*this);
	*this -= 1;
	return ret;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

int Date::operator-(const Date& d)
{
	Date ret(d);
	int i = 0;
	int day = 0;
	while (ret != *this)
	{
		ret += 1;
		day++;
	}
	return day;
}

int main()
{

	return 0;
}

++和–分前置和后置,如果没有用于区分的对象,无法方便是前置还是后置。因此前置被定为默认情况,如果要进行后置++或–的函数重载,需要在声明时,在参数列表处加上int,作为后置的标志,不需要变量名(因为函数不会接收这个值,只是用来判断)。
如有不当之处,请各位看客指正。

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

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

相关文章

springboot整合其他项目

目录 一&#xff0c;集成Druid 学习地址&#xff1a; 主要讲监控 基于springboot视图渲染技术上增加代码 1.1 增加pom依赖 1.2 先在application.yml中添加Druid的数据源 1.3 其次在全局配置文件application.yml中添加所需的配置 配置截图&#xff1a; 配置解析 1.4 启动…

电脑录屏快捷键是什么?win10自带屏幕录制在哪

​在使用电脑的过程中&#xff0c;我们难免会遇到使用电脑录屏功能。有时候可能是想录制网课&#xff0c;有时候可能是想录制游戏的精彩操作&#xff0c;有时候可能只是想录制会议内容。 电脑录屏能够将重要的画面内容进行录制&#xff0c;十分的方便。但也有很多的小伙伴不清…

Python基础(三):PyCharm安装和使用

文章目录 PyCharm安装和使用 一、PyCharm的作用 二、PyCharm系统要求 三、下载和安装 四、PyCharm基本使用 五、PyCharm的基本设置 1、修改主题 2、修改代码文字格式 3、修改解释器 4、项目管理 PyCharm安装和使用 14天学习训练营导师课程&#xff1a;杨鑫《Python…

一、VSCode——免安装

介绍 Visual Studio Code支持可移植模式。此模式使 VS Code 创建和维护的所有数据都位于自身附近&#xff0c;因此可以跨环境移动。 此模式还提供了设置 VS Code 扩展的安装文件夹位置的方法&#xff0c;这对于阻止在 Windows AppData 文件夹中安装扩展的企业环境非常有用。 …

极市打榜|70G+已标注数据集出炉,油品泄露识别等全新算法上线!

极市打榜 算法打榜是极市平台推出的一种算法项目合作模式&#xff0c;至今已上线 100 产业端落地算法项目&#xff0c;已对接智慧城市、智慧工地、明厨亮灶等多个行业真实需求&#xff0c;算法方向涵盖目标检测、行为识别、图像分割、视频理解、目标跟踪、OCR等。 开发者报名…

CAN 协议控制器和物理总线之间的接口芯片SIT1040T 高速 CAN 总线收发器

CAN 协议控制器和物理总线之间的接口芯片SIT1040T 高速 CAN 总线收发器 CAN是最新进的现场总线,灵活性好,通讯可靠性高,抗干扰能力强&#xff0c;超长通信距离等优点,110个节点,兼带CAN-FD功能产品,容错电压可达-70V~ 70V,温度范围高达-40C ~ 150C最初应用于汽车电子,目前已广…

安信可Ai-WB1系列AT指令连接MQTT阿里云物联网平台

文章目录前言1 准备材料2 创建云端设备3 硬件连接4 配置终端设备5 MQTT实现发布&订阅消息联系我们前言 本文将介绍安信可AI-WB1系列通过AT指令接入阿里云物联网平台&#xff0c;实现MQTT的订阅和发布。 1 准备材料 AI-WB1系列模组或者开发板USB转TTL模块/Type-C数据线阿…

数仓建设教程

50000字&#xff0c;数仓建设保姆级教程&#xff0c;离线和实时一网打尽(理论实战) 上 - 腾讯云开发者社区-腾讯云 (tencent.com)50000字&#xff0c;数仓建设保姆级教程&#xff0c;离线和实时一网打尽(理论实战) 下_五分钟学大数据的技术博客_51CTO博客#yyds干货盘点#最强最全…

什么是DDoS攻击?企业服务器是否需要DDoS防御

有时候你可能会遇到某个网站突然打不开&#xff0c;这一段时间后发布自己被DDos攻击的公告&#xff0c; 那么&#xff0c;为什么DDOS攻击能让服务器瘫痪&#xff1f;黑客又如何执行DDos攻击的呢&#xff1f; DDoS全称为Distributed Denial of Service&#xff08;分布式拒绝服…

Anemoi hash:一种SNARK-friendly的哈希函数

随着zk的兴起&#xff0c;出现了一大批zk友好且面向算术化(Arithmetization-Oriented)的哈希函数&#xff0c;如MiMC-Hash, Rescue–Prime, Poseidon等等&#xff0c;本文要介绍的Anemoi是今年新出的一种zk友好且面向算术化的哈希函数&#xff0c;与其他哈希函数相比&#xff0…

让我们进入面向对象的世界(三)

文章目录前言一.了解什么是继承二.我们针对继承来设计一个动物继承树前言2.1 第一步 找出共同属性和行为的对象2.2 设计代表共同状态行为的类2.3 决定子类是否让某项行为有不同的运作方式。2.4我们仔细去观察一下子类的特征&#xff0c;争取更多的抽象化的机会。三.继承的相关语…

leetcode:887. 鸡蛋掉落【经典dp定义】

目录题目截图题目分析ac code总结题目截图 题目分析 变量&#xff1a;鸡蛋的数量&#xff0c;楼层n&#xff0c;尝试的次数m有一个单调性容易发现&#xff1a;尝试的次数越多&#xff0c;能解决楼层越高的确切值另一个单调性&#xff1a;鸡蛋的数量越多&#xff0c;能够解决楼…

Flutter 实现局部刷新 StreamBuilder 实例详解

一、前言 在flutter项目中&#xff0c;页面内直接调用setState方法会使得页面重新执行build方法&#xff0c;导致内部组件被全量刷新&#xff0c;造成不必要的性能消耗。出于性能和用户体验方面的考虑我们经常会使用局部刷新代替全量刷新进行页面更新的操作。包括Provider、Va…

制造业企业如何高效进行生产计划排单?

随着社会的发展&#xff0c;个性化订单需求越来越多。面对如今更加多样化、紧迫化、随机化的订单&#xff0c;企业必须采用科学合理的方式和手段对生产计划进行控制&#xff0c;以提高企业的经济效益。生产计划在实施的过程中&#xff0c;由于一些原因&#xff0c;往往造成实施…

Node.js 模块化及npm概念介绍

文章目录模块化1 模块化的基本概念1.1 什么是模块化1.2 模块化规范2 Nodejs中的模块化2.1 Nodejs中模块的分类2.2 加载模块2.3 模块的作用域2.4 向外共享模块作用域中的成员2.4.1 module对象2.4.2 module.export对象2.4.3 共享成员时的注意点2.4.4 exports对象2.4.5 exportshe …

栈和队列及其多种接口实现-c语言

今天我们来完成栈和队列&#xff0c;首先我们要明白什么是栈&#xff0c;什么是队列。 目录 栈的选择 栈的结构 栈的初始化 栈的销毁 入栈 出栈 返回栈顶元素 计算数据个数 判断是否为空 队列的选择 队列的结构 入队列 出队列 判断是否为空 取队头元素 取队尾…

Java Spring Bean的生命周期 三级缓存

Java Spring Bean的生命周期 三级缓存 SpringBean的生命周期&#xff1a;是从 Bean 实例化之后&#xff08;即通过反射创建出对象之后&#xff09;&#xff0c;到Bean成为一个完整对象&#xff0c;最终存储到单例池中&#xff0c;这个过程被称为Spring Bean的生命周期。Spring…

盘一盘那些年我们使用的Java

一、序 那些年我们使用过的Java版本。我是一个80后&#xff0c;当年在大学时代使用的是Java5&#xff0c;当时是大三的时候学校有了编程课&#xff0c;最开始学的是汇编语言、VB、C然后再是Java。当时就是Java5&#xff0c;搞了个课程设计与顺便也参加了个校园程序设计大赛。当…

MCE | Nrf2 的“戏精”之路

外界刺激 (如药物、紫外线和电离辐射) 和内源性自由基和活性氧 (ROS) 会直接或者间接地损伤蛋白质、脂质和 DNA 等细胞成分&#xff0c;为了抵御这些不利影响&#xff0c;机体形成了一套复杂的氧化应激应答系统来缓解细胞所受的损害。而 Nrf2&#xff0c;作为调控抗氧化应激的一…

SAP ABAP Function Module 的动态调用方式使用方式介绍试读版

在本教程前面的步骤 7&#xff0c;我们介绍了 ABAP Function Module 的基本使用方法&#xff1a; 7. ABAP function module 的使用 最近我的知识星球有朋友提问&#xff1a; 大佬&#xff0c;我想问一下动态获取到物料主数据的字段名之后&#xff0c;如何将获取到的字段名去与…