C++:类和对象(从底层编译开始)详解[前篇]

目录

一.inline内联的详细介绍

(1)为什么在调用内联函数时不需要建立栈帧:

(2)为什么inline声明和定义分离到两个文件会产生链接错误,链接是什么,为什么没有函数地址:

二.类,实例化和this指针

1.类的介绍(class):

2.实例化:

(1)实例化的概念:

(2)实例化的空间分配:

3.this指针:

4.关于空指针访问成员变量的注意点:

三.类的默认成员函数

1.构造函数:

2.析构函数:

3.拷贝构造函数:

4.运算符重载:

四.日期类实现

一.inline内联的详细介绍

为了更清楚的明白类的定义与底层运行逻辑,我先从inline内联开始讲起:

• ⽤inline修饰的函数叫做内联函数编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率 //(1)为什么不需要建立栈帧

• inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定,inline适用于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略(因为内联的展开在需要频繁调用短小函数的代码里,可以大限度上减少函数调用指令(call)的使用,而在其他函数体本身较大的情况下,inline不展开的调用指令的方法可能会显得更为简便) 

• C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不⽅便调 试,C++设计了inline⽬的就是替代C的宏函数

• vs编译器debug版本下⾯默认是不展开inline的,这样方便调试

• inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错//(2)为什么会产生链接错误,链接是什么,为什么没有函数地址

(内联的使用示例)

#include <iostream>// 显式声明为内联函数
inline int add(int a, int b) {return a + b;
}int main() {std::cout << add(3, 5) << std::endl; // 编译器可能将 add(3,5) 展开为 `3 + 5`return 0;
}

上述的阐述乍看总有种似懂非懂的感觉,但一旦深入想想就还有好些东西不明不白,下面我将对这段话中可能会产生的疑问做出一一解答:

(1)为什么在调用内联函数时不需要建立栈帧:

(a).在理解这个问题之前,我们需要先搞明白函数的栈帧是怎么一回事

       简而言之栈帧是程序执行过程中用于保存函数调用状态的临时数据结构,它在函数调用时被创建,返回时销毁。每个栈帧对应一次函数调用,记录了函数的执行上下文信息

以下这张图片就展示了函数Add在调用时所创建的栈帧,而其中的push等相关汇编命令我也附在下面:

        

(b).再让我们区别以下函数的栈帧整体代码的编译和链接的关系:

据上述代码编译的过程而言,函数栈帧的创建属于程序运行时的动态数据结构,虽与编译链接过程的静态代码无关,但编译与链接依旧会在其运行时对其产生影响:如编译阶段为栈帧的创建和销毁生成正确的指令,以及链接阶段确定函数的位置以及符号引用,因此,一般情况下较小的函数被inline展开时,其函数名并不会进入符号表,而是直接在调用处替换代码(发生在预处理中,编译之前),自然也就跟栈帧的创建销毁没啥关系了

(2)为什么inline声明和定义分离到两个文件会产生链接错误,链接是什么,为什么没有函数地址:

  

inline之所以不建议声明定义分离,是因为当我们假设在head.h头文件里定义了内联函数add(自定义函数名)然后分别在a.cpp里定义add函数然后在b.cpp里调用add函数然后运行,那么在对程序进行编译时,会发现对于add函数头文件里只有声明而没有定义,因此编译器会假设add为一个外部函数(这里类似于一般函数的跨文件调用),但与一般函数调用不同的是,一般函数在假设外部函数时会同时在符号表生成一个对函数的引用(包含了未解析的地址),然后再在链接过程中通过对各文件的链接重新补全符号表里未解析的地址,从而实现函数声明定义的分开,但inline函数却不一样,它同样会在符号表里生成一个未解析的地址,但由于inline函数的性质就是对函数体代码的整体替换从而实现对指令代码的节约使用而且需要明确的内联点才可以进行替换,因此这样导致了其无法在链接时找到对应的内联点进而不能像一般函数那样在链接过程中补全对应的符号表里未解析的地址(内联需要替换的代码都找不到更别说地址了),从而发生链接的报错

二.类,实例化和this指针

1.类的介绍(class):

其中有两点需要特别注意

(a) 类中的成员函数默认为内联

(b)关于访问限定符:

如下代码:public和private是访问限定符,在public后面的成员函数和成员变量可以直接在类的外部使用,private后面的成员函数和成员变量不能被直接使用。       

        通常我们把成员函数定义为public,把成员变量定义为private

#include<iostream>
using namespace std;
class TEST
{
public://成员函数void test(){return;}
private://成员变量int _a;int _b;
};
//以上class为类的关键字,TEST为类的名字,{}中的为类的主体//但同样的,C++由于相当于C的pro max版,同时也可以兼容C中的struct结构:
typedef struct ListNodeC
{struct ListNodeC* next;int val;
}LTNode;int main()
{return 0;
}

关于类域

#include<iostream>
using namespace std;class TEST
{
public://成员函数声明int test(int a, int b);private://成员变量int _a;int _b;
};
//类定义了一个新的作用域,类的所有成员函数都在类的作用域中。在类体外定义成员时,需要使用类域名::来访问成员
//如果不指定类域的话,在定义函数时,程序在全局域找不到函数的声明就会报错。编译器不会主动去类域中寻找函数定义
int TEST::test(int a, int b)
{return a + b;
}
int main()
{TEST A;int c = 10; int d = 20;cout << A.test(c, d) << endl;return 0;
}

2.实例化:

(1)实例化的概念:

(2)实例化的空间分配:

 对象的大小只包含成员变量的大小,成员函数不占内存空间

打个比方,现在实例化出了两个类,分别为A,B但A和B的成员变量和地址是不同的,但如果访问这两个类的成员函数,他们都会链接到一个地址(只读存储区,静态存储),所以说我们sizeof(类对象)只用统计成员变量占用的空间

 成员变量占用的空间也符合内存对齐规则:

关于这个对齐其实有点比较容易遗忘,因此我再简述一下:

1. 基本概念
 对齐:数据类型的起始地址必须是该类型大小的整数倍
 例如: int (4字节)的地址必须是  0x4, 0x8, 0xC... 
 未对齐:数据起始地址不满足对齐规则,可能导致性能下降或硬件错误(如 ARM 架构)

2. 内存对齐规则
 a. 自然对齐
 规则:每个数据类型的地址必须是其自身大小的整数倍
 示例:

struct AlignedStruct {char a;        // 1字节 → 地址 0x0int b;        // 4字节 → 地址 0x4(填充3字节)double c;     // 8字节 → 地址 0x8(填充7字节)
};

b. 结构体对齐
成员顺序:成员按声明顺序排列,每个成员按自然对齐对齐

举例:

​
struct CompactStruct {int a;       // 0x0char b;      // 0x4(填充3字节)short c;     // 0x8
}; // 总大小:12字节(而非 16字节)​

3.this指针:

• Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题

• 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。⽐如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day)

• 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this- >_year = year;

• C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使⽤this指针

 另外需要注意一点,this指针其实存放在栈区,而不是对象里面

#include<iostream>
using namespace std;
class Date
{
public:// void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){// this->_year = year;_year = year;this->_month = month;this->_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:// 这⾥只是声明,没有开空间 int _year;int _month;int _day;
};int main()
{Date A;return 0;
}//成员函数在传参时都有一个类的指针类型的this指针,这个this指针编译器不会显示出来,但实际上他是存在的,看上边这串代码,如果再函数调用赋值的时候,可以手动把this指针加上去,这样其实并不会报错。这就说明这个this指针是真实存在的

4.关于空指针访问成员变量的注意点:

先看一下下面这两个代码:

       这两串代码运行的结果并不相同,已知第一个是正常运行,第二个是运行崩溃,首先我们应该知道不管是C语言中还是C++中,解引用空指针并不会编译报错,只会运行崩溃

其次再来分析问什么第二个是运行崩溃

        首先成员函数不会占用物理内存,只有成员变量会,实例出nullptr说明没开空间,但仔细看第一个程序是不需要访问成员变量的,所以不开空间也没有报错,而第二个程序访问了开空间的成员变量:_a,所以运行崩溃了

三.类的默认成员函数

默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数:

接下来我会对其中的几个做出详细介绍:

1.构造函数:

       构造函数也是一种成员函数但他和我们写的普通构造函数不同的是,他是在我们实例化类的对象是默认调用的,也就是说,实例化对象是他自己会去主动调用这个构造函数,其本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数⾃动调⽤的 特点就完美的替代的了Init

接下来说说它的基本特点

函数名和类名相同;

没有返回值:

#include<iostream>
using namespace std;
class DATE
{
public:DATE(int year = 2000, int mouth = 11, int day = 1){_year = year;_mouth = mouth;_day = day;}
private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day;
};
int main()
{DATE d1;return 0;
}//上面这串代码中定义了一个日期类,并实例化出一个对象d1,调试可以看到,实例化d1自动调用了DATE这个构造函数,给d1的三个成员变量进行了赋值//构造函数也有很多种,第一种无参构造函数。第二种是全缺省构造函数,第三种就是不写构造时编译器默认的构造函数(接下来我会具体说说这三种函数),如果我们在实例化的时候只写这个对象就像上面这串代码这样:DATE d1; 这样调用的构造函数叫默认构造

       

//无参构造函数
DATE()
{_year = 1;_mouth = 1;_day = 1;
}//全缺省构造函数
DATE(int year = 2000, int mouth = 11, int day = 1)
{_year = year;_mouth = mouth;_day = day;
}// 带参构造函数 
Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}

       除了以上几点还有一点需要额外注意:如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦用户显式定义编译器将不再⽣成,也就是说我们不写,编译器默认⽣成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于⾃定义类型成员变量,要求调⽤这个成员变量的默认构造函数初始化,  如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要⽤初始化列表才能解决,初始化列表的问题,本文先放一下,下一篇文章再作详细介绍

       读到这里,会发现一个问题就是既然系统会自动生成默认构造函数,那为什么我们还需要自己去写构造函数?举个例子:

当类需要动态分配内存(如 new  或 malloc )时,默认构造函数无法自动释放资源,必须手动管理:

class Buffer {
public:int* data; // 动态内存// 自定义构造函数:初始化 dataBuffer(int size) : data(new int[size]) {std::cout << "Buffer initialized with size " << size << std::endl;}// 析构函数:释放资源~Buffer() {delete[] data;std::cout << "Buffer destroyed" << std::endl;}
};int main() {Buffer buf(1024); // 调用自定义构造函数return 0;
}

默认构造函数不会初始化 data ,导致未定义行为(如悬空指针),自定义构造函数确保 data 正确分配内存

2.析构函数:

       析构函数可以在类对象销毁时自动调用,释放我们的内存空间。就好比之前实现的栈这个数据结构,我们需要把我们malloc出来的空间都free掉,那么这个时候如果是使用c++里面的类来完成的话,在我们的栈销毁时(该对象生命周期结束时)就可以自动调用析构函数释放内存


~Stack()
{cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;
}

析构的特点也很明显:

1. 析构函数名是在类名前加上字符~

2.不需要写返回值

3.和构造函数一样,我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理,⾃定类型成员会调⽤他的析构函数

4.一个类只有一个析构且当类成员不需要释放空间时,不需要自己写析构函数

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};

3.拷贝构造函数:

如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数 也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数

#include<iostream>
using namespace std;class DATE
{
public:DATE(int year, int mouth, int day){_year = year;_mouth = mouth;_day = day;}void Print(){cout << _year << "年" << _mouth << "月" << _day << "日" << endl;}
private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day;
};
int main()
{DATE d1(10,10,10);DATE d2(d1);//调用拷贝构造d1.Print();d2.Print();return 0;
}
//注意,第一个参数必须是引用。否则编译器会报错。为什么会报错呢?理解一下,如果说我们传入的第一个参数没有引用,那么这个形参是得拷贝一份我们的实参,怎么拷贝呢?他还是得调用我们的拷贝构造函数去拷贝,那这就形成了闭环,而这样无限拷贝下去编译器是不允许的//对于没有主动写拷贝构造的类,编译器也会默认生成一个拷贝构造,对于内置类型进行浅拷贝,也就是只拷贝值,对于自定义类型成员会调用他的拷贝构造。

但还有几点需要注意:

1.像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完 成需要的拷⻉,所以不需要我们显⽰实现拷⻉构造,但像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器⾃动⽣成的拷⻉构造完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉),像MyQueue这样的类型内部主要是⾃定义类型 Stack成员,编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造,也不需要我们显⽰实现 MyQueue的拷⻉构造(前提是Stack这个类有析构)

2.传值返回会产⽣⼀个临时对象调⽤拷⻉构造传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤ 引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少拷⻉,但是⼀定要确保返回对象在当前函数结束后还在,才能⽤引⽤返回

4.运算符重载:

运算符重载简而言之就是赋予我们常见的运算符以新的定义与使用场景,比如+号原来只可以用于数字之间的运算,但经过运算符重载之后,使其可以进行日期之间的计算,诸如此类:

bool operator==(DATE x)
{return _year == x._year && _mouth == x._mouth && _day == x._day;
}

以下是几个注意点:

1.不能对c++没有的符号进行重载

2、以下五个运算符不能进行重载:

.*      ::      sizeof       ? :       .

3.运算符重载的参数列表至少要含有一个自定义类型,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y)

4.重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分

四.日期类实现

//Date.h
#pragma once
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class DATE
{
public:DATE(int year = 2000, int mouth = 11, int day = 1){_year = year;_mouth = mouth;_day = day;}//短小多次调用函数使用inline//clase默认inlineint GetMouthDay(int year, int mouth){assert(mouth > 0 && mouth < 13);static int mouthDayArray[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//多次访问直接定义静态数组if (mouth == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))//让容易不通过的条件放前面{return 29;}else return mouthDayArray[mouth];}DATE& operator+=(int day);//声明运算符重载DATE& operator+(int day);void Print(){cout << _year << "年" << _mouth << "月" << _day << "日" << endl;}//日期比较bool operator>(DATE x){if (_year > x._year) return true;else if (_year < x._year) return false;if (_mouth > x._mouth) return true;else if (_mouth < x._mouth) return false;if (_day > x._day) return true;else return false;}bool operator==(DATE x){return _year == x._year && _mouth == x._mouth && _day == x._day;}bool operator < (DATE x){return !(*this > x) && !(*this == x);}bool operator!=(DATE& d2){return !(*this == d2);}DATE operator++(int){//后置加加返回原值//注意这个临时变量出了这个函数就销毁了所以不能引用返回DATE tmp(*this);_day++;if (_day > GetMouthDay(_year, _mouth)){_day = 1; _mouth++;}if (_mouth > 12){_year++;_mouth = 1;}return tmp;}//两日期相减int operator-(DATE& d1);
private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day;
};
//text.cpp#include"DATE.h"DATE& DATE::operator+=(int day)//表明所属类
{//由于更改了自身所以重载的是+=//引用返回可以避免拷贝,节省开销//不能返回空值,不然无法解决这种问题(a+=10)+=10//对于这种情况如果传dATE返回的话也无法改变原值,不符合预期。_day += day;while (_day > GetMouthDay(_year, _mouth)){_day -= GetMouthDay(_year, _mouth);++_mouth;if (_mouth == 13){_year++;_mouth = 1;}}return *this;
}
DATE& DATE::operator+(int day)
{//DATE tmp(*this);//拷贝//默认构造函数DATE tmp = *this;///同样也是调用默认构造函数tmp += day;return tmp;
}
int DATE::operator-(DATE& d1)
{int cnt = 0;int flag = 1;DATE max = *this;DATE min = d1;if (max < min){flag = -1;max = d1;min = *this;}while (max != min){cnt++;min++;}return cnt * flag;
}

以上就是关于日期类相关的函数代码了

欧克,时间也不晚了,就到这里吧

全文终

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥】-动态规划-倒水

目录 一、问题描述​ 二、解题思路 三、完整代码 二维dp 使用滚动数组 一、问题描述 二、解题思路 一个变种的01背包问题&#xff1a; 不选该物品&#xff1a;获得固定收益 e 选择方案1&#xff1a;消耗体积 a&#xff0c;获得价值 b 选择方案2&#xff1a;消耗体积 c&…

【软考网工-实践篇】DHCP 动态主机配置协议

一、DHCP简介 DHCP&#xff0c;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议。 位置&#xff1a;DHCP常见运行于路由器上&#xff0c;作为DHCP服务器功能&#xff1a;用于自动分配IP地址及其他网络参数给网络中的设备作用&#xff1a;简化网络管理&…

使用 Arduino 和 ThingSpeak 通过互联网进行实时温度和湿度监测

使用 ThingSpeak 和 Arduino 通过 Internet 进行温度和湿度监控 湿度和温度是许多地方(如农场、温室、医疗、工业家庭和办公室)非常常见的测量参数。我们已经介绍了使用 Arduino 进行湿度和温度测量,并在 LCD 上显示数据。 在这个物联网项目中,我们将使用ThingSpeak在互联…

电子电子架构 --- 车载ECU信息安全

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

有关Spring 简介和第一个Spring案例:基于XML配置的IoC容器

1.Spirng是什么? Spring 是一个分层的 轻量级开源框架&#xff0c;专为简化企业级Java应用开发而设计。 它由Rod Johnson于2003年提出&#xff0c;核心目标是解决企业应用开发的复杂性&#xff0c;通过 控制反转&#xff08;IoC&#xff09; 和 面向切面编程&#xff08;AOP&…

警惕!Ollama大模型工具的安全风险及应对策略

文章目录 **Ollama的安全隐患&#xff1a;不容忽视的风险****未授权访问&#xff1a;门户洞开的风险****数据泄露&#xff1a;敏感信息的外泄****漏洞利用&#xff1a;历史遗留的隐患** **安全加固&#xff1a;守护数据与服务的防线****限制监听范围&#xff1a;内网隔离的保护…

Qt从入门到入土(十) -数据库操作--SQLITE

认识 数据库是用于存储、管理和检索数据的系统化集合。它是一种按照特定结构组织数据的存储方式&#xff0c;通过软件&#xff08;数据库管理系统&#xff0c;DBMS&#xff09;来实现数据的高效存储、查询、更新和管理。通过文件存储数据适用于少量的数据&#xff0c;而当拥有…

嵌入式2-按键

一、按键 1.原理图&#xff1a; P14按下低电平&#xff0c;不按则高电平。 if((t&(1<<5))!0)& 优先级 8 ! 优先级 7 二、STC89Cxx中文参考手册 1.ram(随机访问存储器&#xff09;易失性 1.1sram&#xff08;512字节&#xff09;静态存储器 2.rom(只读存储…

论文分享 | HE-Nav: 一种适用于复杂环境中空地机器人的高性能高效导航系统

阿木实验室始终致力于通过开源项目和智能无人机产品&#xff0c;为全球无人机开发者提供强有力的技术支持&#xff0c;并推出了开源项目校园赞助活动&#xff0c;助力高校学子在学术研究与技术创新中取得更大突破。近日&#xff0c;香港大学王俊铭同学&#xff0c;基于阿木实验…

平安养老险广西分公司2025年“3∙15”金融消费者权益教育宣传活动暨南湖公园健步行活动

2025年3月11日&#xff0c;由国家金融监督管理总局广西监管局、中国人民银行广西壮族自治区分行指导&#xff0c;平安养老保险股份有限公司&#xff08;以下简称“平安养老险”&#xff09;广西分公司联合平安银行南宁分行、平安人寿广西分公司、平安产险广西分公司、平安证券广…

学习threejs,使用MeshFaceMaterial面材质容器

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshFaceMaterial 二…

电脑内存不足怎么办?

常规解决方法盘点 关闭后台程序&#xff1a;按下【Ctrl Shift Esc】组合键打开任务管理器&#xff0c;在 “进程” 选项卡里&#xff0c;把当前不用的程序统统 “结束任务” &#xff0c;像那些自动更新的软件、常驻后台的播放器&#xff0c;关了能释放不少内存。比如音乐软…

Excel中国式排名,3种方法!

大家好&#xff0c;我是小鱼。 什么是中国式排名呢&#xff1f; 举个例子比如说公司一共有10名员工进行成绩考核&#xff0c;如果9个人考核成绩都是90分&#xff0c;你是89分&#xff0c;按照国际惯用的排名法则&#xff1a;9 个人考核成绩并列第一&#xff0c;你第10名&…

deepseek+kimi做ppt教程记录

1.首先注册deepseek和kimi deepseek官网&#xff1a;https://chat.deepseek.com/ kimi官网&#xff1a;https://kimi.moonshot.cn/ 以下以一篇工作总结报告为例 2.使用deepseek生成ppt大纲 让deepseek生成kimi生成ppt所需要的内容时&#xff0c;需要注意提示词内容&#xff0c;…

前端无限滚动内容自动回收技术详解:原理、实现与优化

文章目录 一、核心需求与技术挑战1.1 无限滚动的问题症结1.2 自动回收的三大目标 二、技术实现原理2.1 虚拟滚动核心机制2.2 关键技术指标 三、完整实现方案3.1 基础HTML结构3.2 CSS关键样式3.3 JavaScript核心逻辑3.3.1 滚动控制器3.3.2 动态尺寸处理 四、性能优化策略4.1 内存…

【训练细节解读】文本智能混合分块(Mixtures of Text Chunking,MoC)引领RAG进入多粒度感知智能分块阶段

RAG系统在处理复杂上下文时,传统和语义分块方法的局限性,文本分块的质量限制了检索到的内容,从而影响生成答案的准确性。尽管其他算法组件有所进步,但分块策略中的增量缺陷仍可能在一定程度上降低整体系统性能。如何直接量化分块质量?如何有效利用大型语言模型(LLMs)进行…

Jmeter下载及环境配置

Jmeter下载及环境配置 java环境变量配置配置jdk环境变量检查是否配置成功JMeter下载 java环境变量配置 访问地址&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/ 注意&#xff1a;需要自己注册账号 下载完成&#xff0c;解压后的目录为&#xff1a; …

coze ai assistant Task 2

创建一个智能体&#xff1a;夸夸机器人 https://www.coze.cn/store/agent/7480939060010713138?bot_idtrue 改为豆包系列-豆包角色扮演 添加bingWebSearch搜索 添加前&#xff1a; 添加后&#xff1a; 改为工具调用&#xff1a; 添加知识库 使用长期记忆 结合自己的需求&…

Unity基于C#+UGUI解决方案,制作每日签到系统(本地存储签到数据)

一、需求介绍:基于本地存储系统制作一个每日签到系统界面,相关签到界面如下图所示,点击“签到有礼”按钮后就会跳转到“每日登录礼”这个界面,点击“立即签到”按钮之后,按钮就会置灰,而且按钮的文字会变成“等待明日”。 二、制作界面显示相关功能,需要在Unity中新建一…

多线程(超详细) (ε≡٩(๑>₃<)۶ 一心向学)

多线程目录 一、认识线程 1、概念&#xff1a; 1) 线程是什么 2) 线程为什么存在 3) 进程与线程的区别 二、创建线程 1、方法1&#xff1a;继承Thread类 2、方法2&#xff1a;实现 Runnable 接口 3、方法3&#xff1a;匿名内部类创建 Thread 子类对象 4、方法4&#…