【C++】构造函数、初始化列表,析构函数,拷贝构造函数,运算符重载

 注:本博客图片来源于学习笔记: 学习笔记icon-default.png?t=N7T8https://gitee.com/box-he-he/learning-notes

完整思维导图请前往该博主码云下载。


目录

 注:本博客图片来源于学习笔记: 学习笔记https://gitee.com/box-he-he/learning-notes

完整思维导图请前往该博主码云下载。

一、构造函数

构造函数的形式及其使用:

初始化列表:

explicit关键字

二、析构函数

1 .概念

2. 特性

析构函数的调用顺序

三、拷贝构造函数

特性:

四、运算符重载(部分)

1、概念

2、赋值运算符重载

3、前置++和后置++的实现


 

一、构造函数

构造函数是一种特殊的成员函数,在创建对象时自动调用,用于初始化对象的成员变量和执行其他必要的操作。它的名称与类名相同,没有返回类型,并且可以被重载。

构造函数有以下几个重要的特点:

  1. 构造函数的名称与类名相同,包括大小写和命名空间。
  2. 构造函数没有返回类型。
  3. 构造函数可以被重载,即可以定义多个具有不同参数列表的构造函数。
  4. 构造函数可以有默认参数,从而允许在创建对象时省略某些参数。
  5. 构造函数可以有任意数量的初始化列表,用于按照指定顺序初始化对象的成员变量。
  6. 构造函数可以访问类的所有成员变量和成员函数。
  7. 构造函数在创建对象时自动调用,无需手动调用。
  8. 对象的整个生命周期只调用一次。

构造函数主要用于以下几个方面(功能):

  1. 初始化成员变量:构造函数通过参数或初始化列表来初始化对象的成员变量,确保对象在创建时具有特定的初始值。
  2. 分配内存或资源:如果对象需要动态分配内存或管理其他资源(如文件句柄),构造函数可以在创建对象时进行相应的操作,从而确保对象可以正确地使用这些资源。
  3. 执行必要的操作:有时候,创建对象可能需要执行一些必要的操作,比如打开文件等,构造函数可以在创建对象时执行这些操作。

需要注意以下几点:

  1. 一个类可以有多个构造函数,它们具有不同的参数列表。这被称为构造函数的重载。
  2. 如果没有显式地定义构造函数,编译器会自动生成一个默认构造函数,但它只会对自定义类型变量进行默认初始化,对内置类型(int, double, float等)无法初始化。
  3. 编写构造函数时应该根据类的需求来初始化成员变量,并且可以根据需要执行其他必要的操作。
  4. 如果自定义了构造函数,编译器将不再生成默认构造函数。如果需要同时拥有默认构造函数和自定义构造函数,可以提供默认参数或者显式定义一个无参数的默认构造函数。

构造函数的形式及其使用:

默认构造函数包括:1、无参构造函数;2、全缺省的构造函数;3、编译器默认生成的构造函数 

当用户自己定义构造函数时 ,必须存在一个默认构造函数。

构造函数的使用:

 class Date{public:// 1.无参构造函数(默认构造函数)Date(){}// 2.带参构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}// 3.全缺省的构造函数(默认构造函数)Date(int year = 2024, int month = 2, int day = 6){_year = year;_month = month;_day = day;}// 4.编译器默认生成的构造函数(默认构造函数)private:int _year;int _month;int _day;};void TestDate(){Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象// warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)Date d3();}

需要注意的是全缺省的构造函数和无参的构造函数都属于默认构造函数,不能同时存在。

同时 函数2 与 函数3 无法构成函数重载,会造成函数的重定义,也无法同时存在。

 补充:由于编译器默认生成的构造函数无法对内置类型进行初始化,在C++11标准中,对此引入了解决方案:在变量声明时可以为其提供默认值。

 class Date{private:int _year = 2024;int _month = 2;int _day = 6;};void TestDate(){Date d; // 此时d的私有成员初始化为2024/2/6}

 

初始化列表:

1、基本形式

初始化列表:以一个 冒号开始 ,接着是一个以 逗号分隔的数据成员列表 ,每个 " 成员变量 " 后面跟
一个 放在括号中的初始值或表达式。
class Date
{
public:
Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:
int _year;
int _month;
int _day;
};
【注意】
1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员(且该类没有其默认构造函数时)        
class A
{
public:A(int a):_a(a){}
private:int _a;
};
class B
{
public:B(int a, int ref):_aobj(a), _ref(ref), _n(10){}
private:A _aobj;  // 没有默认构造函数的自定义类型int& _ref; // 引用const int _n; // const 
};

特性:

1、即使不在初始化列表中初始化自定义类型成员,其也会在初始化列表中隐式地调用其构造函数进行初始化。

2、初始化列表的执行顺序是其在类中的声明顺序,与初始化列表中的顺序无关。

explicit关键字

explicit 是一个关键字,用于修饰单参数构造函数,它可以防止编译器进行隐式的类型转换。在 C++ 中,当我们定义一个单参数构造函数时,编译器会自动进行隐式类型转换,将参数类型转换为目标类型,然后调用该构造函数来创建对象。而使用 explicit 关键字修饰的构造函数将被标记为禁止隐式类型转换。

下面是两个具体的示例来说明 explicit 关键字的作用:

1、单参构造函数

class MyClass {
public:explicit MyClass(int x) : value(x) {}int getValue() const {return value;}private:int value;
};int main() {MyClass obj1(5);       // 直接调用带有 int 参数的构造函数int val1 = obj1.getValue();MyClass obj2 = 10;    // 编译错误!禁止隐式类型转换int val2 = obj2.getValue();return 0;
}

在上述示例中,MyClass 类定义了一个带有单参数的构造函数,并使用 explicit 关键字进行修饰。这意味着我们只能通过显式地调用构造函数来创建对象,而不能进行隐式的类型转换。在 main 函数中,我们可以看到以下几点:

  1. 创建 obj1 对象时,我们直接调用了构造函数,不会发生隐式类型转换。这是合法的。

  2. 尝试使用 obj2 = 10; 进行从 int--->MyClass 隐式类型转换时,编译器会抛出错误。因为我们使用了 explicit 关键字,禁止隐式类型转换。

2、半缺省的构造函数

class MyClass {
public://虽然有多个参数,但是创建对象时后两个参数可以不传递,使用explicit修饰,// 不具有类型转换作用,编译不通过explicit MyClass(int x, int y = 1, int z = 1) : value(x), data(y), temp(z){}int getValue() const {return value;}private:int value;int data;int temp;
};int main() {MyClass obj1(5);       // 直接调用带有 int 参数的构造函数int val1 = obj1.getValue();MyClass obj2 = 10;    // 编译错误!禁止隐式类型转换int val2 = obj2.getValue();return 0;
}

二、析构函数

1 .概念

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?              

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由    

编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

【注意】:析构函数只负责销毁占用的额外资源,即额外申请的内存空间,例如:malloc,new等。而对象本身,如果定义在函数中,则其本身存在于栈区中,随着函数的栈帧一同销毁,与析构函数无关。

2. 特性

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

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

2. 无参数无返回值类型。

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构

函数不能重载

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");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);
}

 

析构函数的调用顺序

  


三、拷贝构造函数

拷贝构造函数(Copy Constructor)是一种特殊的构造函数,它接受一个对象作为参数,用于创建一个新的对象,这个新对象与原始对象具有相同的值。

在C++中,如果我们没有显式定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。默认拷贝构造函数执行的是逐个成员的拷贝,将源对象的每个成员变量的值复制给新创建的对象。

以下是一个简单的示例来说明拷贝构造函数的用法:

class MyClass {
public:int value;// 拷贝构造函数MyClass(const MyClass& other) {value = other.value;}
};int main() {MyClass obj1;obj1.value = 10;MyClass obj2(obj1);  // 使用拷贝构造函数创建新对象// 或者 MyClass obj2 = obj1;return 0;
}

在上述示例中,我们定义了一个名为 MyClass 的类,并在其中定义了一个拥有一个整数成员变量 value 的对象。然后我们在 main 函数中创建了两个对象 obj1 和 obj2

  • obj1 是通过默认构造函数创建的,并将 value 设置为 10。

  • obj2 是通过拷贝构造函数创建的,它的参数是另一个 MyClass 对象 obj1。在拷贝构造函数中,我们将 obj1 的值复制给了 obj2

需要注意的是,拷贝构造函数的参数应该是一个 const 引用(const MyClass& other),以确保不会修改被传递的源对象。

拷贝构造函数在以下情况下会被隐式调用:

  1. 通过赋值运算符(=)进行对象的初始化。
  2. 将一个对象作为函数的参数传递给另一个对象。
  3. 从一个函数返回对象时。

需要注意的是,当类中包含指针成员变量时,需要手动定义拷贝构造函数,以确保指针指向独立的内存,避免浅拷贝引发的指针悬挂问题。

 

特性:

1. 拷贝构造函数是构造函数的一个重载形式

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

 

 为什么值传递会引起无穷递归呢?为什么引用不会呢?

  答:假如参数不是引用,是值传递,那么传递给函数的值其实就是实参的一个临时拷贝,那在对实参进行临时拷贝时还是需要再次去调用我Date类里的拷贝构造函数,由于一直进行的是值传递,所以这个过程是无限递归的。但是如果拷贝构造函数的参数是对实参的引用,就不需要对实参再进行临时拷贝。引用是实参的一个别名,他们指向的也是同一块内存,所以不需要传递值,而是通过实参的引用来对实参的内存进行读写。

3. 若未显式定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按

    字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time(const Time& t){_hour = t._hour;_minute = t._minute;_second = t._second;cout << "Time::Time(const 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 d1;// 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数// 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构//造函数Date d2(d1); // Date d2 = d1; 也是默认调用的拷贝函数return 0;
}

 【注意】:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?

当然像日期类这样的类是没必要的。

但是对于初始化时成员需要额外申请内存的类,此时我们使用默认拷贝函数会发生程序崩溃,这时我们必须手动创建一个拷贝构造函数进行深拷贝。例如下面的栈class Stack;

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;}// 如果我们在这只是进行简单的值拷贝,程序将会崩溃Stack(const Stack& s){_array = new DataType[_capacity];memcpy(_array, s._array, _size * sizeof(DataType));_size = s._size;_capacity = s._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;
}

 

【注意】:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
 

5. 拷贝构造函数典型调用场景:     

  • 使用已存在对象创建新对象

  • 函数参数类型为类类型对象

  • 函数返回值类型为类类型对象

class MyClass {
public:int value;// 拷贝构造函数MyClass(const MyClass& other) {value = other.value;}
};MyClass Test(const MyClass obj3)
{MyClass temp;return temp; // 函数返回值类型为类类型对象// 由于temp为局部变量,在函数结束后不存在,所以需对temp进行临时拷贝,// 返回值的实质是temp的一份临时拷贝
}int main() {MyClass obj1;obj1.value = 10;MyClass obj2(obj1);  // 或者 MyClass obj2 = obj1;使用已存在的对象创建新对象Test(obj2);          // 函数的参数类型为类类型对象return 0;
}

四、运算符重载(部分)

1、概念

C++ 为了增强代码的可读性引入了运算符重载 运算符重载是具有特殊函数名的函数 ,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字 operator 后面接需要重载的运算符符号
函数原型: 返回值类型  operator 操作符 ( 参数列表 )
【注意】:
  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少 1 ,因为成员函数的第一个参数为隐
    藏的 this
  5. .* :: sizeof ?: . 注意以上5个运算符不能重载。

2、赋值运算符重载


1、重载运算符的格式

  • 参数类型:const T&,传递引用可以提高传参效率

  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

  • 检测是否自己给自己赋值

  • 返回*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;}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;
};

 

2. 赋值运算符只能重载成类的成员函数不能重载成全局函数

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

【注意】:如果需要在全局中重载其他运算符,需要给两个参数。因为只有类的非静态成员函数具有this指针,全局函数没有。

3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

【注意】:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值。
 

3、前置++和后置++的实现

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 前置++:返回+1之后的结果// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率Date& operator++(){_day += 1;return *this;}// 后置++:// 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载// C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器//自动传递// 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存//一份,然后给this + 1// 而temp是临时对象,因此只能以值的方式返回,不能返回引用Date operator++(int){Date temp(*this);_day += 1;return temp;}
private:int _year;int _month;int _day;
};int main()
{Date d;Date d1(2022, 1, 13);d = d1++; // d: 2022,1,13 d1:2022,1,14d = ++d1; // d: 2022,1,15 d1:2022,1,15return 0;
}

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

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

相关文章

微信小程序(三十六)事件传参

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.传参步骤 2.传参接收解构步骤 源码&#xff1a; index.wxml <button type"primary" bind:tap"onclick" mark:index"{{0}}" mark:remb"{{1}}" class"But&quo…

我的QQ编程学习群

欢迎大家加入我的QQ编程学习群。 群号:950365002 群里面有许多的大学生大佬&#xff0c;有编程上的疑惑可以随时问&#xff0c;也可以聊一些休闲的东西。 热烈欢迎大家加入&#xff01;&#xff01; 上限:150人。

华视 CVR-100UC 身份证读取 html二次开发模板

python读卡&#xff1a;python读卡 最近小唐应要求要开发一个前端的身份证读卡界面&#xff0c;结果华视CVR-100UC 的读取界面是在是有点&#xff0c;而且怎么调试连官方最基本的启动程序都执行不了。CertReader.ocx 已成功&#xff0c;后面在问询一系列前辈之后&#xff0c;大…

uniapp 使用renderjs引入echarts

效果图&#xff1a; 1.1renderjs引入echarts 组件zmui-echarts.vue&#xff1a; <template><view class"zmui-echarts" :prop"option" :change:prop"echarts.delay"></view> </template><script>export defaul…

时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型 LSTM(长短期记忆)是一种递归神经网络(RNN)的变体,它在序列数据建模方面表现出色。电力负荷预测是一项重要的任务,可以利用LSTM神经网络…

【华为 ICT HCIA eNSP 习题汇总】——题目集13

1、以下在项目规划阶段中需要完成的工作是&#xff08;&#xff09;。 A、确定技术方案 B、了解项目背景 C、选择网络产品 D、规划 IP 地址 考点&#xff1a;网络规划与设计 解析&#xff1a;&#xff08;B&#xff09; 确定技术方案是在网络规划的设计阶段完成的工作&#xff…

vue - 指令(一)

看文章可以得到什么&#xff1f; 1.可以快速的了解并会使用vue的指令 2.可以加深你对vue指令的理解&#xff0c;知道每个指令代表什么功能​​​​​​​ 目录 什么是vue的指令&#xff1f;​​​​​​​ vue常见指令的使用 v-html v-show v-if v-else 和v-else-…

c#cad 创建-正方形(四)

运行环境 vs2022 c# cad2016 调试成功 一、程序说明 创建一个正方形&#xff0c;并将其添加到当前活动文档的模型空间中。 程序首先获取当前活动文档和数据库&#xff0c;并创建一个编辑器对象。 然后&#xff0c;使用事务开始创建正方形的操作。获取模型空间的块表记录&a…

「 CISSP学习笔记 」08. 安全运营

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 理解并遵守调查执行记录和监控活动执行配置管理 (CM)&#xff08;例如&#xff0c;预配、基线、自动化&#xff09;应用基本的安全操作概念应用资源保护执行事故管理执行和维护检测和预防措施实施…

electron项目在内网环境的linux环境下进行打包

Linux需要的文件: electron-v13.0.0-linux-x64.zip appimage-12.0.1.7z snap-template-electron-4.0-1-amd64.tar.7z 下载慢或者下载失败的情况可以手动下载以上electron文件复制到指定文件夹下&#xff1a; 1.electron-v13.0.0-linux-x64.zip 复制到~/.cache/electron/目录下…

百面嵌入式专栏(面试题)进程管理相关面试题1.0

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍进程管理相关面试题 。 一、进程管理相关面试题 进程是什么?操作系统如何描述和抽象一个进程?进程是否有生命周期?如何标识一个进程?进程与进程之间的关系如何?Linux操作系统的进程0是什么?Linux操…

简单的TcpServer(英译中)

目录 一、TCP socket API 详解1.1 socket()1.2 bind()1.3 listen()1.4 accept()1.5 connect 二、TcpServer&#xff08;英译中&#xff09;2.1 TcpServer.hpp2.2 TcpClient.cc2.3 Task.hpp2.4 Thread.hpp2.5 ThreadPool.hpp2.6 makefile2.7 Main.cc2.8 log.hpp2.9 Init.hpp2.10…

vue3项目中的404页面

vue3项目中的404页面 春节前的最后一篇技术博客了 写了不少vue项目&#xff0c;发现一直没有正确处理404页面。404页面的出现有这么几种可能&#xff1a; 错误输入了页面地址路由连接跳转时&#xff0c;某些路由已经不存在了&#xff0c;而程序员并没有正确处理 也就是说40…

PDF文件格式(一):交叉引用流

在PDF-1.5版本之前&#xff0c;对象的交叉引用信息是存储在交叉引用表(cross-reference table)中的。在PDF-1.5版本之后&#xff0c;引进了交叉引用流(cross-reference stream)对象&#xff0c;可以用它来存储对象的交叉引用信息&#xff0c;就像交叉引用表的功能一样。 采用交…

小白代码审计入门

最近小白一直在学习代码审计,对于我这个没有代码审计的菜鸟来说确实是一件无比艰难的事情。但是着恰恰应了一句老话:万事开头难。但是小白我会坚持下去。何况现在已经喜欢上了代码审计,下面呢小白就说一下appcms后台模板Getshell以及读取任意文件,影响的版本是2.0.101版本。…

Pyhton专项进阶——http协议、cookie、session和认证-3

关于cookie的报文首部相关属性熟悉后&#xff0c;下面就是实际应用。 使用cookie实现用户登录验证&#xff08;初步&#xff09;&#xff1a; 思路&#xff08;一&#xff09;&#xff1a;显示登录页面&#xff0c;输入用户和密码&#xff0c;后端验证&#xff0c;如果验证通…

【TCP】四次挥手(终止连接)

前言 TCP&#xff08;传输控制协议&#xff09;是互联网协议&#xff08;IP&#xff09;中的一种重要传输层协议&#xff0c;用于在通信的计算机之间建立可靠的、有序的和错误校验的数据传输。在TCP连接中&#xff0c;数据传输是双向的&#xff0c;因此需要一种机制来开始和结…

Mac上新版InfluxDB使用教程

一、简介 官网&#xff1a;influxdb 二、influxdb安装 建议使用Homebrew在 macOS 上安装 InfluxDB v2&#xff1a; brew install influxdb启动influxdb服务&#xff1a;brew services start influxdb 停止influxdb服务&#xff1a;brew services stop influxdb 查看是否启…

docker 运行jar包 指定配置文件

要在Docker中运行JAR包并指定配置文件&#xff0c;你可以创建一个Dockerfile来定义你的容器环境&#xff0c;并在其中指定如何运行JAR包和配置文件。下面是一个简单的例子&#xff0c;展示了如何在Dockerfile中设置这些配置&#xff1a; 第一步&#xff1a;创建 Dockerfile文件…

《MySQL》超详细笔记

目录 基本知识 主流数据库 数据库基本概念 MySQL启动 数据库基本命令 数据库 启动数据库 显示数据库 创建数据库 删除数据库 使用数据库 查询当前数据库信息 显示数据库中的表 导入数据库脚本 表 查看表的结构 查看创建某个表的SQL语句 数据库的查询命令 查询…