C++初阶(五)--类和对象(中)--默认成员函数

目录

一、默认成员函数(Default Member Functions)

 二、构造函数( Constructor)

1.构造函数的基本概念

2.构造函数的特征

3.构造函数的使用

无参构造函数 和 带参构造函数

注意事项:

4.默认构造函数

隐式生成的默认构造函数:

默认构造函数的特性 :

注意事项:

5.构造函数的特性

三、析构函数(Destructor)

1.析构函数的基本概念

2.析构函数的特征

3.析构函数的使用

4.默认析构函数

5.析构顺序问题

6.析构函数特性

四、 拷贝构造函数

1.定义

2.拷贝构造函数的特性

3.拷贝构造函数的用法

对象初始化

函数返回值按值返回

4.拷贝构造函数的深拷贝与浅拷贝

5.引用传参(面试题)


一、默认成员函数(Default Member Functions)

如果一个类中什么成员都没有,简称为空类
空类中真的什么都没有吗?并不是,任何类在什么都不写时编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数

class Date {};

 二、构造函数( Constructor)

1.构造函数的基本概念

构造函数是一种特殊的成员函数,它在对象创建时自动调用,用于初始化对象的成员变量。构造函数的名字必须与类名完全相同,并且没有返回类型。

注意:构造函数只是初始化对象,不开辟空间创建对象。

2.构造函数的特征

构造函数是特殊的成员函数,主要特征如下:

  • 构造函数的函数名和类名是相同的 (比如类名是 Date,构造函数名就是 Date)
  • 构造函数无返回值 (它不具有返回类型,因此不能直接返回值)
  • 构造函数支持重载 (仔细看下面的例子)
  • 会在对象实例化时自动调用对象定义出来。

3.构造函数的使用

 无参构造函数 和 带参构造函数

#include <iostream>  
using namespace std;class MyClass 
{
public:MyClass() {cout << "无参构造函数被调用" << endl;}MyClass(int val){value = val;cout << "带参数的构造函数被调用,值为: " << value << endl;}
private:int value;};int main() 
{MyClass obj1; // 调用无参构造函数,注意后面没有括号哦~  MyClass obj2(10); // 调用带参数的构造函数  return 0;
}

运行结果:

解读:不给参数时就会调用 无参构造函数,给参数则会调用 带参构造函数。 

注意事项:

 构造函数是特殊的,不是常规的成员函数,不能直接调

class Date 
{
public:Date(int year = 1, int month = 1, int day = 0) {_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main(void)
{Date d1;d1.Date(); // 不能这么去调,构造函数是特殊的,不是常规的成员函数!return 0;
}

 

 如果通过无参构造函数创建对象,对象后面不用跟括号,否则就成了函数声明。 

#include <iostream>  
using namespace std;class MyClass 
{
public:MyClass() {cout << "无参构造函数被调用" << endl;}MyClass(int val){value = val;cout << "带参数的构造函数被调用,值为: " << value << endl;}void Print(){cout << "lllll" << endl;}private:int value;};int main() 
{MyClass obj1(); // 调用无参构造函数  obj1.Print();MyClass obj2(10); // 调用带参数的构造函数  obj2.Print();return 0;
}

 带上括号:

不带括号:

 这里如果调用带参构造函数,我们需要传递三个参数(这里我们没设缺省) 。 

 如果你没有自己定义构造函数(类中未显式定义),C++ 编译器会自动生成一个无参的默认构造函数。当然,如果你自己定义了,编译器就不会帮你生成了。 

class Date 
{
public://如果用户显式定义了构造函数,编译器将不再生成/* Date(int year, int month, int day){_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(void)
{Date d1;d1.Print();return 0;
}

 输出结果:

没有定义构造函数,对象也可以创建成功,因此此处调用的是 编译器默认生成的构造函数。

接下来,我们来讲一下默认构造函数。 

4. 默认构造函数

概念:

默认构造函数是一种没有参数或参数全部有默认值的构造函数。当没有为类显式定义任何构造函数时,编译器会自动生成一个默认的无参构造函数。这个构造函数通常不会执行任何初始化操作,但它是存在的,可以用于创建类的对象。

无参构造函数、全缺省构造函数、自动生成的构造函数都被称为 默认构造函数

并且 默认构造函数只能有一个!

隐式生成的默认构造函数:

#include <iostream>  
using namespace std;class MyClass 
{
public:// 没有显式定义任何构造函数  
};int main() 
{MyClass obj; // 调用隐式生成的默认构造函数  return 0;
}

在这个例子中,MyClass没有显式定义任何构造函数,因此编译器会为其生成一个默认的无参构造函数。在main函数中创建MyClass类型的对象obj时,会调用这个隐式生成的默认构造函数。

默认构造函数的特性 :

  1. 无参或全默认参数:默认构造函数要么没有参数,要么所有参数都有默认值。
  2. 自动生成:当类中没有显式定义任何构造函数时,编译器会自动生成一个默认构造函数。
  3. 初始化成员变量:虽然隐式生成的默认构造函数不会执行任何自定义的初始化操作,但它仍然会调用成员变量的默认构造函数(如果成员变量是类的对象)。

成员变量的默认构造函数调用 :代码示例

#include <iostream>  
using namespace std;class Member 
{
public:Member() {cout << "Member默认构造函数被调用" << endl;}
};class MyClass 
{
private:Member member;
public:// 没有显式定义任何构造函数  
};int main() 
{MyClass obj; // 调用隐式生成的默认构造函数,同时调用Member的默认构造函数  return 0;
}

 输出:

在这个例子中,MyClass包含了一个Member类型的成员变量。当创建MyClass类型的对象时,隐式生成的默认构造函数会调用Member的默认构造函数来初始化member。 

注意事项:

语法上无参和全缺省可以同时存在,但如果同时存在会引发二义性:

class Date 
{
public:Date() {_year = 1970;_month = 1;_day = 1;}Date(int year = 1970, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};int main(void)
{Date d1;return 0;
}

5.构造函数的特性

通过刚才的讲解我们知道了任何一个类的默认构造函数,只有三种:

  • 无参的构造函数
  • 全缺省的构造函数
  • 我们不写,编译器自己生成的构造函数

如果你没有自己定义构造函数(类中未显式定义),C++ 编译器会自动生成一个无参的默认构造函数。当然,如果你自己定义了,编译器就不会帮你生成了。

代码:

class Date 
{
public:// 让编译器自己生成一个void Print() {printf("%d-%d-%d\n", _year, _month, _day);}private:int _year;int _month;int _day;
};int main(void)
{Date d1;  // 这里调用的是默认生成的无参的构造函数d1.Print();return 0;
}

关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会 生成默认的构造函数。但是看起来默认构造函数又没什么用?d1对象调用了编译器生成的默 认构造函数,但是d1对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的 默认构造函数并没有什么用?

解答:

C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类 型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,看看 下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员 函数。

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 _t;
};int main()
{Date d;return 0;
}

 运行结果:

对于用户定义的类型(如类、结构体),如果它们没有定义自己的构造函数,编译器会生成一个默认的无参数构造函数(也称为“合成默认构造函数”)。这个构造函数会按成员变量在类中声明的顺序调用它们的默认构造函数(如果有的话)。

代码示例:

#include <iostream>  
#include <string>  class MemberClass 
{  
public:  MemberClass() {  std::cout << "MemberClass default constructor called" << std::endl;  }  
};  class MyClass 
{  
public:  MemberClass member; // 用户定义类型成员变量  // MyClass没有定义自己的构造函数,所以编译器会生成一个默认构造函数  
};  int main() 
{  MyClass obj; // 调用MyClass的默认构造函数,它会调用MemberClass的默认构造函数  return 0;  
}

 在上面的代码中,当MyClass的对象obj被创建时,它的成员变量member会被初始化,这会调用MemberClass的默认构造函数。

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。

#include<iostream>
using namespace std;
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:// 基本类型(内置类型)int _year = 2024;int _month = 12;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;d.Print();return 0;
}

注意:构造函数遵循先定义先构造原则。 

三、析构函数(Destructor)

1.析构函数的基本概念

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

对象在销毁时会自动调用析构函数,完成对象的一些资源清理工作。

2. 析构函数的特征

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

class MyClass 
{
public:~MyClass() {// 释放资源的代码  std::cout << "Destructor called!" << std::endl;}
};

在上面的例子中,~MyClass() 是 MyClass 类的析构函数。

3.析构函数的使用

在我们前面学习栈的实现的时候,动态开辟后的内存需要手动进行释放,但是我们很有可能会忘记释放,因为即使不释放空间,程序也可以正常运行。如果使用析构函数,那么会自动调用,能够有效减少忘记释放的可能。 

#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 4)//全缺省默认构造函数{_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc fail!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data)//入栈{// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack()//析构函数{if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}

我们在设置栈的构造函数时,定义容量 capacity 时利用缺省参数默认给个4的容量,这样用的时候默认就是4,如果不想要4可以自己传。

如此一来,就可以保证了栈被定义出来就一定被初始化,用完后会自动销毁。以后就不会有忘记调用 destroy 而导致内存泄露的惨案了,这里的析构函数就可以充当销毁的作用。

4.默认析构函数

关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

#include<iostream>
using namespace std;
class Time
{
public:~Time(){cout << "~Time()" << 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;
}
// 程序运行结束后输出:~Time()

在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类生成的默认析构函数。

 5.析构顺序问题

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1){_year = year;}~Date(){cout << "~Date()->" << _year << endl;}
private:// 基本类型(内置类型)int _year;int _month;int _day;
};
void func()
{Date d3(3);//局部对象static Date d4(4);//局部的静态
}
Date d5(5);//全局对象
static Date d7(7);//全局静态
Date d6(6);
static Date d8(8);// 局部对象(后定义先析构) -》 局部的静态 -》全局对象(后定义先析构)
int main()
{Date d1(1);//局部对象 Date d2(2);func();return 0;
}

析构函数执行顺序:局部对象(后定义先析构) -》 局部的静态 -》全局对象(后定义先析构) 

6.析构函数特性

📌 如果不自己写构造函数,让编译器自动生成,那么这个自动生成的 默认构造函数:

对于 "内置类型" 的成员变量:不会做初始化处理。
对于 "自定义类型" 的成员变量:会调用它的默认构造函数(不用参数就可以调的)初始化,如果没有默认构造函数(不用参数就可以调用的构造函数)就会报错!
 而我们的析构函数也是这样的。

📌 如果我们不自己写析构函数,让编译器自动生成,那么这个 默认析构函数:

对于 "内置类型" 的成员变量:不作处理 。
对于 "自定义类型" 的成员变量:会调用它对应的析构函数  。

四、 拷贝构造函数

在C++编程中,拷贝构造函数是一个非常重要的概念,它用于创建一个新对象,作为现有对象的副本。拷贝构造函数在对象复制、函数参数传递、返回值以及容器操作等场景中扮演着关键角色。

1.定义

拷贝构造函数是一种特殊的构造函数,它接受一个同类型的对象作为参数,并用于初始化新创建的对象。其语法如下:

类名(const 类名& 形参);
ClassName(const ClassName& other);

这里,ClassName 是类的名称,other 是传递给拷贝构造函数的参数,它是一个常量引用,以避免不必要的对象复制。

2.拷贝构造函数的特性

它也是一个特殊的成员函数,所以他符合构造函数的一些特性:

① 拷贝构造函数是构造函数的一个重载形式。函数名和类名相同,没有返回值。

② 拷贝构造函数的参数只有一个,并且 必须要使用引用传参!

3.拷贝构造函数的用法

对象初始化

class Date {
public:Date(int year = 0, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}/* Date d2(d1); */Date(Date& d) {         // 这里要用引用,否则就会无穷递归下去_year = d._year;_month = d._month;_day = d._day;}void Print() {printf("%d-%d-%d\n", _year, _month, _day);}private:int _year;int _month;int _day;
};int main(void)
{Date d1(2024, 10, 9);Date d2(d1);          // 拷贝复制// 看看拷贝成功没d1.Print();d2.Print();return 0;
}

 运行结果:

函数返回值按值返回

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;}void Print() {std::cout << _year << "-" << _month << "-" << _day << std::endl;}private:int _year;int _month;int _day;
};Date Birthday()
{Date time(2004, 10, 29);return time;// 可能会调用拷贝构造函数来返回对象的副本}int main()
{Date T = Birthday();// 拷贝构造函数被调用,用返回的对象副本初始化 Treturn 0;
}

在这个例子中,Birthday函数返回一个对象,当这个对象被返回并用于初始化 T 时,可能会调用拷贝构造函数来创建 T。 

4.拷贝构造函数的深拷贝与浅拷贝

除了上面提到的基本用法,拷贝构造函数还涉及到深拷贝和浅拷贝的概念。

浅拷贝

默认情况下,C++ 的拷贝构造函数执行的是浅拷贝。这意味着它只是简单地复制对象的成员变量值。如果成员变量是基本类型(如 intchar 等),那么浅拷贝没有问题。但如果成员变量是指针或引用类型,浅拷贝就可能会导致问题。

class ShallowPerson {
private:std::string* namePtr;int age;public:ShallowPerson(std::string n, int a) {namePtr = new std::string(n);age = a;}// 浅拷贝构造函数(默认情况下的拷贝构造函数行为)ShallowPerson(const ShallowPerson& other) {namePtr = other.namePtr;age = other.age;std::cout << "浅拷贝构造函数被调用,可能会有问题哦!😕" << std::endl;}~ShallowPerson() {delete namePtr;}void introduce() {std::cout << "我叫 " << *namePtr << ",我 " << age << " 岁啦!" << std::endl;}
};int main() 
{ShallowPerson sp1("酒鬼猿", 20);ShallowPerson sp2 = sp1;sp1.introduce();sp2.introduce();// 当其中一个对象被销毁时,可能会导致另一个对象出现问题return 0;
}

 

 在这个例子中,浅拷贝只是复制了指针的值,而不是复制指针所指向的内容。这就导致两个对象的指针指向了同一块内存。当其中一个对象被销毁并释放内存时,另一个对象的指针就变成了悬空指针,再使用这个指针就会导致未定义的行为。

深拷贝

为了解决浅拷贝的问题,我们需要实现深拷贝。深拷贝会复制对象的所有成员变量,包括指针所指向的内容。

class DeepPerson {
private:std::string* namePtr;int age;public:DeepPerson(std::string n, int a) {namePtr = new std::string(n);age = a;}// 深拷贝构造函数DeepPerson(const DeepPerson& other) {age = other.age;namePtr = new std::string(*(other.namePtr)); // 复制指针所指向的内容std::cout << "深拷贝构造函数被调用,一切都好啦!😀" << std::endl;}~DeepPerson() {delete namePtr;}void introduce() {std::cout << "我叫 " << *namePtr << ",我 " << age << " 岁啦!" << std::endl;}
};int main() {DeepPerson dp1("酒鬼猿", 21);DeepPerson dp2 = dp1;dp1.introduce();dp2.introduce();// 现在即使一个对象被销毁,另一个对象也不会受到影响return 0;
}

 

在深拷贝构造函数中,我们为新对象分配了新的内存,并将原对象指针所指向的内容复制到新内存中。这样,两个对象就拥有了各自独立的内存空间,不会相互影响。 

 5.引用传参(面试题)

面试题: 为什么必须使用引用传参呢?

解答:

当我们使用值传递的方式传递参数时,实际上是将实参复制一份传递给函数的形参。这意味着会创建一个新的对象,这个新对象是实参的副本。

假设我们有一个类 MyClass,如果拷贝构造函数不使用引用传参,如下所示:

class MyClass 
{
public:int value;MyClass(MyClass obj) { value = obj.value;}
};

当我们使用一个已有的对象去初始化另一个新对象时,比如这样的代码:

MyClass obj1;
obj1.value = 10;
MyClass obj2(obj1);

在这个过程中,会调用拷贝构造函数来初始化 obj2。但是,由于拷贝构造函数的参数是按值传递的,所以在调用拷贝构造函数时,会将 obj1 复制一份传递给拷贝构造函数的形参 obj。而这个复制的过程又会触发拷贝构造函数的调用,因为要创建形参 obj 的副本。这样就形成了一个无限递归的过程。

具体来说,当执行 MyClass obj2(obj1); 时:

  1. 首先尝试调用拷贝构造函数来创建 obj2,将 obj1 作为实参传递给拷贝构造函数。
  2. 由于拷贝构造函数是按值传递参数,所以要创建形参 obj 的副本,这就需要再次调用拷贝构造函数。
  3. 第二次调用拷贝构造函数时,又要创建新的形参副本,再次触发拷贝构造函数的调用。
  4. 这个过程会不断重复下去,直到程序耗尽栈空间而崩溃。

为了避免这种无限递归的情况,拷贝构造函数的参数应该使用引用类型,当使用引用传参时,形参只是实参的一个别名,不会创建新的对象副本。这样在调用拷贝构造函数时,就可以直接使用传入的对象进行初始化,而不会触发新的拷贝构造函数调用,从而避免了无限递归的问题。

本篇博客到此结束,如果大家浏览后发现什么错误之处,或者有什么问题,评论区留言哦~

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

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

相关文章

Node-RED开源项目的modbus通信(TCP)

一、Modbus 通信协议 Modbus是一种串行通信协议&#xff0c;是Modicon公司&#xff08;现在的施耐德电气 Schneider Electric&#xff09;于1979年为使用可编程逻辑控制器&#xff08;PLC&#xff09;通信而发表。Modbus已经成为工业领域通信协议的业界标准&#xff08;De fact…

大数据比对,shell脚本与hive技术结合

需求描述 从主机中获取加密数据内容&#xff0c;解密数据内容&#xff08;可能会存在json解析&#xff09;插入到另一个库中&#xff0c;比对原始库和新库的相同表数据的数据一致性内容。 数据一致性比对实现 上亿条数据&#xff0c;如何比对并发现两个表数据差异 相关流程…

重庆大学软件工程考研,难度如何?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重大软件专业可谓是最好上岸的985院校&#xff01;重庆大学24考研各大学院复试录取情况已出&#xff0c; 我们先说学硕部分&#xff1a; 招生人数&#xff1a; 重庆大学软件工程学硕近几年计划统招人数都不多&#xf…

【 截稿倒计时 | JPCS独立出版 | 检索快速稳定】第三届能源与动力工程国际学术会议(EPE 2024)

第三届能源与动力工程国际学术会议&#xff08;EPE 2024&#xff09; 2024 3rd International Conference on Energy and Power Engineering 2024年10月18日 线上会议 往届平均会后3个月完成见刊及EI检索&#xff0c;检索快速稳定~ EPE 2023 EI检索 EPE 2023 Scopus检索 …

麒麟aarch64架构下安装compat-openssl10

问题描述&#xff1a; 麒麟aarch64架构下安装mysql8.0.40,报错nothing provides libcrypto.so.10()(64bit) needed by 原因&#xff1a; 你当前系统的 OpenSSL 版本与 MySQL 8.0.40 所需的库不匹配。MySQL 8.0.40 需要 libcrypto.so.10&#xff0c;而你的系统使用的是 OpenS…

maven编译时引入外部jar

<!-- 1.添加对工程lib目录中jar的编译 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> …

力扣(leetcode)每日一题 3191 使二进制数组全部等于 1 的最少操作次数 I |贪心

3191. 使二进制数组全部等于 1 的最少操作次数 I 题干 给你一个二进制数组 nums 。 你可以对数组执行以下操作 任意 次&#xff08;也可以 0 次&#xff09;&#xff1a; 选择数组中 任意连续 3 个元素&#xff0c;并将它们 全部反转 。 反转 一个元素指的是将它的值从 0 …

Git_GitHub

Git_GitHub 创建远程仓库 远程仓库操作 创建远程仓库别名 基本语法 案例实操 推送本地分支到远程仓库 基本语法 案例实操 拉取代码 基本语法 案例实操 克隆远程仓库到本地 基本语法 案例实操 邀请加入团队 选择邀请合作者 填入想要合作的人 复制邀请函 接受邀…

C语言笔记(数据的存储篇)

目录 1.数据类型的详细介绍 2.整型在内存中的存储&#xff1a;原码、反码、补码 3.大小端字节序介绍及判断 4.浮点型的内存中的存储解析 1.数据类型的详细介绍 下述是内置类型&#xff1a; char // 字符数据类型 short // 短整型 int // 整型 long …

MySQL-事务Transaction详解

文章目录 事务概述事务基本概念事务四大特性(ACID)演示MySQL事务手动开启事务MySQL默认事务机制 事务的隔离级别隔离级别基本概述三种现象脏读不可重复读幻读 查看和设置隔离级别四种隔离级别及演示读未提交(read uncommitted)读提交(read committed)可重复读(repeatable read)…

快速了解K8S几种网络实现

Kubernetes 的网络实现是通过容器网络接口&#xff08;CNI&#xff09;插件来实现的&#xff0c;这些插件提供了不同的网络模型和功能。常见的Kubernetes网络实现&#xff0c;包括&#xff1a;Flannel、Calico、Weave Net。 1. Flannel Flannel 是一个简单的 Kubernetes 网络…

sql-labs靶场第十八关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、寻找注入点 2、注入数据库 ①寻找注入方法 ②爆库&#xff0c;查看数据库名称 ③爆表&#xff0c;查看security库的所有表 ④爆列&#xff0c;查看users表的所有列 ⑤成功获取用户名…

用Spring AI 做智能客服,基于私有知识库和RAG技术

Java智能客服系统运用RAG技术提升答疑精准度 基于Spring ai 的 RAG&#xff08;检索增强生成&#xff09;技术&#xff0c;Java智能客服系统能够利用私有知识库中的信息提供更准确的答疑服务。 它的核心思路是&#xff1a; 首先&#xff0c;将客服QA以Word形式导入到系统中&…

基于FreeRTOS的LWIP移植

目录 前言一、移植准备工作二、以太网固件库与驱动2.1 固件库文件添加2.2 库文件修改2.3 添加网卡驱动 三、LWIP 数据包和网络接口管理3.1 添加LWIP源文件3.2 Lwip文件修改3.2.1 修改cc.h3.2.2 修改lwipopts.h3.2.3 修改icmp.c3.2.4 修改sys_arch.h和sys_arch.c3.2.5 修改ether…

量子门电路开销——T门、clifford门、toffoli门、fredkin门

在量子计算中&#xff0c;T门的成本比Clifford门高出很多倍的原因与量子计算中纠错的实现、物理门操作的复杂性以及容错量子计算架构中的成本评估有关。以下是几个关键原因&#xff0c;解释了为什么 T 门的成本在量子计算中远远高于 Clifford 门&#xff1a; 1. T 门和 Cliffo…

录微课专用提词器,不会被录进视频中的提词器,还能显示PPT中备注的内容

不坑提词器&#xff0c;全称&#xff1a;不坑隐形提词器。是一款能够在截图、录屏、直播过程中隐藏界面的提词器软件。 系统要求&#xff1a;Win10 1024 以上&#xff08;特别提醒&#xff1a;Win7状态下不可隐身&#xff09; ⏬下载 提词器默认放在不坑盒子的安装目录下&…

go生成二维码

go生成二维码 安装二维码依赖库代码实现代码说明 安装二维码依赖库 go get github.com/skip2/go-qrcode代码实现 package mainimport ("fmt""github.com/skip2/go-qrcode""os" )func main() {// 要编码的文本text : "https://www.test.co…

百易云资产管理运营系统 ufile.api.php SQL注入漏洞复现

0x01 产品描述&#xff1a; 百易云资产管理运营系统&#xff0c;是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理&#xff0c;包括资产的登记、盘点、评估、处置等多个环节&#xff0c;同时提供强大的运营分析功能&#…

基于STM32设计的生猪健康检测管理系统(NBIOT+OneNet)(240)

文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成1.2 设计思路1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】项目背景【5】摘要1.4 开发工具的选择【1】设备端开发【2】上位机开发1.5 系统功能总结1.6 系统框架图…

SQL Injection | MySQL 手工注入全流程

0x01&#xff1a;MySQL 手工注入 —— 理论篇 手工注入 MySQL 数据库&#xff0c;一般分为以下五个阶段&#xff0c;如下图所示&#xff1a; 第一阶段 - 判断注入点&#xff1a; 在本阶段中&#xff0c;我们需要判断注入点的数据类型&#xff08;数字型、字符型、搜索型、XX 型…