当前位置: 首页 > news >正文

【C++从入门到放弃】类和对象(中)———类的六大默认成员函数

🧑‍💻作者: @情话0.0
📝专栏:《C++从入门到放弃》
👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢!

在这里插入图片描述

类和对象(中)

  • 前言
  • 一、构造函数
    • 1. 构造函数的概念
    • 2. 构造函数的特性
  • 二、析构函数
    • 1. 析构函数的概念
    • 2. 析构函数的特征
  • 三、 拷贝构造函数
    • 1. 拷贝构造函数的概念
    • 2. 拷贝构造函数的特征
  • 四、 赋值运算符重载
    • 1.运算符重载
    • 2. 赋值运算符重载
  • 四、const成员函数
  • 五、取地址及const取地址操作符重载
  • 总结


前言

  在上一篇文章中提到过空类的存在,它的大小为一个字节,目的就是为了标识这个类的存在。但是空类中真的什么都没有吗?当然不是的,任何类在什么都不写时,编译器会自动生成以下六个默认成员函数。而这六个默认成员函数只会在用户没有显式定义的情况下被编译器自动生成,如若用户自己显示定义了这几个函数,那么编译器不会自动生成默认的成员函数。编译器自动生成的函数称为默认成员函数。

在这里插入图片描述


一、构造函数

1. 构造函数的概念

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d;d.Init(2000, 1, 9);d.Print();return 0;
}

  在创建了一个类对象,可以通过公有方法 Init 给对象设置日期,但如果每次创建对象时都调用该方法设置信息,那是不是有点麻烦,那能否在对象创建时,就将信息设置进去呢?

  构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

2. 构造函数的特性

  构造函数是特殊的成员函数,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主要任务并不是开空间创建对象,而是初始化对象。

其特征如下:

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
class Date
{
public :// 1.无参构造函数Date (){}// 2.带参构造函数Date (int year, int month, int day){_year = year ;_month = month ;_day = day ;}
private :int _year ;int _month ;int _day ;
};
int main()
{Date d1; // 调用无参构造函数Date d2 (2000, 1, 9); // 调用带参的构造函数
}
  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
class Date
{
public:/*// 如果用户显式定义了构造函数,编译器将不再生成Date(int year, int month, int day){_year = year;_month = month;_day = day;} */ void Print(){cout << _year << "-" << _month << "-" << _day << endl;} 
private:int _year;int _month;int _day;
}; 
int main()
{ // 将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数// 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成// d1对象并没有初始值,所以应该去调用无参构造函数或者全缺省构造函数,而显示定义的构造函数并非默认构造函数Date d1;return 0;
}
  1. 无参的构造函数全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个
    注意:无参构造函数、全缺省构造函数、编译器默认生成的构造函数,都是默认成员函数。
class Date
{ 
public:Date()//无参的构造函数{_year = 1900 ;_month = 1 ;_day = 1;}Date (int year = 2000, int month = 1, int day = 9)//全缺省构造函数{_year = year;_month = month;_day = day;}
private :int _year ;int _month ;int _day ;
};

上面的代码会有问题,因为同时出现了两个默认构造函数,当定义了一个无初始值的对象时,编译器就不知道该去调用哪个构造函数。

  1. 关于编译器生成的默认成员函数,我们会发现,不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又好像没什么用?一个对象调用了编译器生成的默认构造函数,但是这个对象的年月日依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用?其实这也算是C++的小缺点吧,可能祖师爷在这个点上并没有想那么多。

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

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。 当你在定义对象时给了初始值,那么就会使用你所给的初始值,若没给初始值,那么就会使用这个在声明时给到的默认值,避免随机值的出现。

class Date
{
private:// 基本类型(内置类型)
int _year = 2000;
int _month = 1;
int _day = 9;// 自定义类型
Time _t;
};

二、析构函数

1. 析构函数的概念

  通过对构造函数的学习,明白了一个对象是怎样来的,那么一个对象又是怎么没的呢?
  析构函数与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类对象的资源清理工作。

2. 析构函数的特征

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

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  5. 编译器生成的默认析构函数,对会自定类型成员调用它的析构函数。
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类,其中包含四个成员变量,其中一个为自定义类型变量,在创建了Date类对象时不仅通过Date类的构造函数对内置类型的三个变量初始化,还要去调用自定义类型变量对应的构造函数完成初始化,那么程序退出时首先要完成对Date类对象的析构,除此之外,还要对Time类完成析构函数,因为在Date类中为完成 _t 的初始化而调用了Time类的构造函数。
  创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数。

三、 拷贝构造函数

1. 拷贝构造函数的概念

  拷贝构造函数是通过一个已经创建好的类对象去创建每一个一摸一样的类对象,只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

2. 拷贝构造函数的特征

  拷贝构造函数也是特殊的成员函数,其特征如下:

1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

class Date
{
public:Date(int year = 2000, int month = 1, int day = 9){_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; 
}

   至于为什么不能使用传值的方式调用拷贝构造函数,原因在于:通过 d1对象去拷贝构造一个新对象 d2 ,而采用传值的方式会对 d1 重新创建一个临时对象 d ,这个创建临时对象的过程又被认为是一个拷贝构造的过程,那么就又会去调用拷贝构造函数,以此类推就会出现拷贝构造函数的无穷递归,而采用传引用的方式就不会出现创建临时对象这个过程。
在这里插入图片描述

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);return 0;
}

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

4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

// 这里会发现下面的程序会崩溃掉,原因就在于析构函数
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;}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;
}

  通过调试发现,对象 s1 和对象 s2 的其中一个参数(array)的地址是一样的,这也就问题所在。

  通过构造函数创建了一个类对象 s1 ,并为其开辟了十字节的空间,然后再为其中存入了4个元素;
  s2 对象使用 s1 拷贝构造,而 Stack 类中没有显式定义拷贝构造函数,则编译器会给 Stack 类生成一个默认的拷贝构造函数,默认的拷贝构造函数是按值拷贝的,即将对象 s1 中的所有内容拷贝给 s2 (s1类对象中第一成员变量是一个地址,相当于把地址复制给了 s2)那么 s1 和 s2 中的 第一个成员变量指向了同一块空间;
  当程序退出时,s1 和 s2 都要销毁,s2 先销毁,通过析构函数将 _array 数组那块空间释放掉,但是对象 s1 并不知道这块空间已经释放,当它再次通过析构函数释放空间时就出现程序崩溃。

注意:类中如果没有涉及资源(堆内存空间、文件指针等)管理时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

5. 拷贝构造函数的典型应用场景

使用已存在对象创建新对象
函数参数类型为类类型对象
函数返回值类型为类类型对象

class Date
{
public:Date(int year, int month, int day){cout << "Date(int,int,int):" << this << endl;} Date(const Date& d){cout << "Date(const Date& d):" << this << endl;}~Date(){cout << "~Date():" << this << endl;}private:int _year;int _month;int _day;
};Date Test(Date d)
{Date tmp(d);return tmp;
}int main()
{Date d1(2000,1,9);Test(d1);return 0;
}

在这里插入图片描述

为了提高程序效率,一般在对象传参时尽量使用引用类型,返回可根据实际场景选择是否也可以选择引用返回。

四、 赋值运算符重载

1.运算符重载

   C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

  函数名字为:关键字operator后面接需要重载的运算符符号。

  函数原型:返回值类型 + operator + 操作符 + (参数列表)

注意:

★ 不能通过连接其他符号来创建新的操作符:比如operator@
★ 重载操作符必须有一个类类型
★ 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义
★ 作为类成员的重载函数时,其形参看起来比操作数数目少1,因为成员函数中有一个默认的形参this,限定为第一个形参
★ .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。

class Date
{ 
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month; _day = day;}// bool operator==(Date* this, const Date& d2)// 这里需要注意的是,左操作数是this指向的调用函数的对象bool operator==(const Date& d2){return _year == d2._year;&& _month == d2._month&& _day == d2._day;}
private:int _year;int _month;int _day;
};
int main ()
{Date d1(2023, 1, 9);Date d2(2000, 1, 9);cout<<(d1 == d2)<<endl; return 0;
}

2. 赋值运算符重载

1. 赋值运算符重载格式:

参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义

class Date
{ 
public :Date(int year = 2000, int month = 1, int day = 9){_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. 赋值运算符只能重载成类的成员函数不能重载成全局函数

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){ _year = year;_month = month;_day = day;}int _year;int _month;int _day;
};// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}// 编译失败:
// error C2801: “operator =”必须是非静态成员

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

3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝(浅拷贝)。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time& operator=(const Time& t){if (this != &t){_hour = t._hour;_minute = t._minute;_second = t._second;}return *this;}private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本类型(内置类型)int _year = 2000;int _month = 1;int _day = 1;// 自定义类型Time _t;
};int main()
{Date d1;Date d2;d1 = d2;return 0;
}

  既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。这就和拷贝构造是一个道理。

四、const成员函数

  将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

在这里插入图片描述

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Display(){cout << "Display()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Display() const{cout << "Display()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}
private:int _year; // 年int _month; // 月int _day; // 日};int main()
{Date d1(2023, 3, 1);d1.Display();const Date d2(2023, 3, 1);d2.Display();return 0;
}

在这里插入图片描述
注意:const 修饰成员函数有两种:

  1. 当const 处在成员函数的最前面时,它代表的意思是该函数的返回值不可被修改;
  2. 当const 处在成员函数的最末尾时,它代表的意思是该函数的成员变量不可被修改。

五、取地址及const取地址操作符重载

class Date
{ 
public :Date* operator&(){return this ;}const Date* operator&()const{return this ;}
private :int _year ; int _month ; int _day ; 
};

  这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有在特殊的情况下,才需要重载,比如你想让获取到指定的内容!


总结

以上就是对类的六大默认成员函数的简单介绍,掌握了这些知识,对后面的C++学习会有很大的步骤,我也相信自己会一步一步往前走,更上一层楼!

相关文章:

【C++从入门到放弃】类和对象(中)———类的六大默认成员函数

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《C从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 类和对…...

白盒测试重点复习内容

白盒测试白盒测试之逻辑覆盖法逻辑覆盖用例设计方法1.语句覆盖2.判定覆盖(分支覆盖)3.条件覆盖4.判定条件覆盖5.条件组合覆盖6.路径覆盖白盒测试之基本路径测试法基本路径测试方法的步骤1.根据程序流程图画控制流图2.计算圈复杂度3.导出测试用例4.准备测试用例5.例题白盒测试总…...

【13】linux命令每日分享——groupadd建立组

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…...

《第一行代码》 第十章:服务

一&#xff0c;在子线程中更新UI 1&#xff0c;新建项目&#xff0c;修改布局代码 <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"&g…...

简单介绍编程进制

十进制 十进制的位权为 10&#xff0c;比如十进制的 123&#xff0c;123 1 * 10 ^ 2 2 * 10 ^ 1 3 * 10 ^ 0。 二进制 二进制的位权为 2&#xff0c;比如十进制的 4&#xff0c;二进制为 100&#xff0c;4 1 * 2 ^ 2 0 * 2 ^ 1 0 *2 ^ 0。 Java7 之前&#xff0c;不支…...

windows忘记开机密码怎么办

windows忘记开机密码怎么办 清除windows登录密码 清除windows登录密码简单方法 开机到欢迎界面时&#xff0c;按CtrlAltDelete两次&#xff0c;跳出帐号窗口&#xff0c;输入用户名&#xff1a;administrator&#xff0c;回车&#xff0c; 或者启动时按F8 选“带命令行的安全…...

SpringCloud:Eureka

目录 一、eureka的作用 二、搭建Eureka服务端 三、添加客户端 四、服务发现 提供者与消费者 服务提供者&#xff1a;一次业务中&#xff0c;被其它微服务调用的服务。&#xff08;提供接口给其它微服务) 服务消费者&#xff1a;一次业务中&#xff0c;调用其它微服务的服…...

如何获取或设置CANoe以太网网卡信息(SET篇)

CAPL提供了一系列函数用来操作CANoe网卡。但是,但是,首先需要明确一点,不管是获取网卡信息,还是设置网卡信息,只能访问CAPL程序所在的节点下的网卡,而不是节点所在的以太网通道下的所有网卡 关于第一张图中,Class节点下,有三个网卡:Ethernet1、VLAN 1.100、VLAN 1.200…...

【软件测试面试题】项目经验?资深测试 (分析+回答) 我不信你还拿不到offer......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 在面试过程中&#…...

tensorflow lite简介-移动设备端机器学习

TensorFlow Lite 是一组工具&#xff0c;可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型&#xff0c;以便实现设备端机器学习。 支持多平台 支持多种平台&#xff0c;涵盖 Android 和 iOS 设备、嵌入式 Linux 和微控制器。 原理/流程 工作原理或者使用流程就是上面…...

Node.js常用知识

1、什么是 Node.js 【】Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。浏览器是 js 的前端运行环境&#xff0c;node.js 是 js 的后端运行环境。他们都有 V8 引擎&#xff0c;有各自的内置 API 2、fs 文件系统模块 【】fs 模块是 Node.js 官方提供的、用来操作文件…...

踩坑:maven打包失败的解决方式总结

Maven打包失败原因总结如下&#xff1a; 失败原因1&#xff1a;无法使用spring-boot-maven-plugin插件 使用spring-boot-maven-plugin插件可以创建一个可执行的JAR应用程序&#xff0c;前提是应用程序的parent为spring-boot-starter-parent。 需要添加parent的包spring-boot…...

【C++】位图

文章目录位图概念位图操作位图代码位图应用位图概念 boss直接登场&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中❓ 40亿个整数&#xff0c;大概就是16GB。40亿个字节大概就是4GB。 1Byt…...

蓝桥杯-考勤刷卡

蓝桥杯-考勤刷卡1、问题描述2、解题思路3、代码实现1、问题描述 小蓝负责一个公司的考勤系统, 他每天都需要根据员工刷卡的情况来确定 每个员工是否到岗。 当员工刷卡时, 会在后台留下一条记录, 包括刷卡的时间和员工编号, 只 要在一天中员工刷过一次卡, 就认为他到岗了。 现在…...

如何利用站内推广和站外推广提高转化率?

在如今的网络时代&#xff0c;拥有一个好的网站是非常重要的。但是&#xff0c;光有一个好的网站是不够的&#xff0c;为了达到我们的目标&#xff0c;需要不断地提高网站的转化率。而在实现这个目标的过程中&#xff0c;站内推广和站外推广是两个非常关键的因素。 站内推广是…...

Java多线程(三)——线程池及定时器

线程池就是一个可以复用线程的技术。前面三种多线程方法就是在用户发起一个线程请求就创建一个新线程来处理&#xff0c;下次新任务来了又要创建新线程&#xff0c;而创建新线程的开销是很大的&#xff0c;这样会严重影响系统的性能。线程池就相当于预先创建好几个线程&#xf…...

Linux命令行安装Oracle19c教程和踩坑经验

安装 下载 从 Oracle官方下载地址 需要的版本&#xff0c;本次安装是在Linux上使用yum安装&#xff0c;因此下载的是RPM。另外&#xff0c;需要说明的是&#xff0c;Oracle加了锁的下载需要登录用户才能安装&#xff0c;而用户是可以免费注册的&#xff0c;这里不做过多说明。 …...

Linux常用命令等

目录 1.Linux常用命令 (1)系统命令 (2)文件操作命令 2.vim编辑器 3.linux系统中,软件安装 (1) rpm 安装,RedHat Package Manager (2)yum 安装 (3)源代码编译安装 1.Linux常用命令 Linux命令是非常多的,对于像嵌入式开发工程师,运维工程师需要掌握的命令是非常多的.对于…...

CEC2014:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2014(提供MATLAB代码

一、鱼鹰优化算法简介 鱼鹰优化算法&#xff08;Osprey optimization algorithm&#xff0c;OOA&#xff09;由Mohammad Dehghani 和 Pavel Trojovsk于2023年提出&#xff0c;其模拟鱼鹰的捕食行为。 鱼鹰是鹰形目、鹗科、鹗属的仅有的一种中型猛禽。雌雄相似。体长51-64厘米…...

MyBatis底层原理【源码运行时序图】

MyBatis初始化流程&#x1f6f7; 以下代码为例&#x1f389; &#x1f387;可对应源码阅读 MyBatis初始化流程✨ #mermaid-svg-yoG1e8Dnp3UIAOUW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yoG1e8Dnp3UIAOU…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...