33 类与对象 · 下

目录

一、构造函数的深入

(一)构造函数的其他特点

(二)使用例

1、Date类与Time类显示写

2、Date类与Time类写一部分

(三)总结

(四)初始化顺序小题目

二、类型转化

(一)内置类型转化到自定义类型

(二)自定义类型转自定义类型

(三)实现例

(四)总结

三、静态成员

(一)静态成员的特点

(二)使用例

(三)练习题目

1、题目一

2、题目二

四、友元

(一)友元的特点

(二)使用例

        1、友元函数

        2、友元类

五、内部类

(一)内部类特点

(二)代码实现

六、匿名对象

(一)匿名对象特点

(二)使用例

(三)总结

七、编译器优化


一、构造函数的深入

(一)构造函数的其他特点

        • 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个【放在括号中的】初始值或表达式。简单来说,就是:跟在参数成员列表后面,冒号开始,逗号分隔,没有结束符号(每个成员变量只能初始化一次)

        • 每个成员变量在初始化列表中只能出现一次,在语法理解上可以认为初始化列表是每个成员变量定义初始化的地方

        • 引用成员变量const成员变量没有默认构造的类类型变量(三种构造函数都没有),必须放在初始化列表位置进行初始化,否则会编译报错。【为什么是这三类:①引用成员变量只能在在定义时初始化,不存在空引用。②const修饰成员变量只能在定义时进行初始化,因为定义时初始化时唯一一次能改变变量的机会。③类类型的成员变量没有默认构造函数的话就会报错。

        • C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

        • 尽量使用初始化列表初始化,因为那些你不在初始化列表进行初始化的成员也会过一次初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表进行初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。

        • 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。

(二)使用例

1、Date类与Time类显示写

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class Time
{
public:Time(int hour)//无默认构造(三种):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date(int& x, int year = 1, int month = 1, int day = 1):_year(year)//初始化列表, _month(month), _day(day), _t(12), _ref(x), _n(1){// error C2512: “Time”: 没有合适的默认构造函数可用,必须在初始化列表进行初始化// error C2530 : “Date::_ref” : 必须初始化引用(&)// error C2789 : “Date::_n” : 必须初始化常量限定(const)类型的对象}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;Time _t; // 没有默认构造int& _ref; // 引用const int _n; // const
};
int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

2、Date类与Time类写一部分

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date():_month(2){cout << "Date()" << endl;}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}
private:// 注意这里不是初始化,这里给的是缺省值,这个缺省值是给初始化列表的// 如果初始化列表没有显示初始化,默认就会用这个缺省值初始化int _year = 1;int _month = 1;int _day;Time _t = 1;const int _n = 1;int* _ptr = (int*)malloc(12);
};int main()
{Date d1;d1.Print();return 0;
}

(三)总结

        无论是否显示写初始化列表,每个构造函数都有初始化列表。

         无论是否在初始化列表显示写初始化,每个成员变量都要走一次初始化列表进行初始化,所以构造函数初始化成员,尽量使用初始化列表

        ③ 在main函数进行的是整体对象的初始化,在初始化列表中是对每个成员变量的初始化。

        ④ 可以使用初始化列表进行初始化,也可以使用函数体中的构造函数进行初始化;可以两者取其一,也可以一起都用。

        ⑤ 可以在成员变量声明的时候给缺省值,若在初始化列表中对成员变量进行了初始化,那么缺省值就会被忽视,反之就会使用缺省值。

        ⑥ 初始化优先级:初始化列表 > 缺省值 > 默认构造函数(无默认构造就报错)。

(四)初始化顺序小题目

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2 = 2;int _a1 = 2;
};int main()
{A aa(1);aa.Print();
}

        结果为:1和随机值。

        解析:初始化顺序要看成员变量声明的顺序,不看初始化列表的顺序;所以先初始化_a2,但_a1还没进行初始化且是内置类型,此时_a1的值为随机值,所以_a2为随机值,初始玩_a2后再把传过去的1初始化_a1,此时_a1就是1。

二、类型转化

(一)内置类型转化到自定义类型

        • C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数

        •  构造函数前面加 explicit 就不再支持隐式类型转换。

          内置类型转化到自定义类型作用:简化写法。

(二)自定义类型转自定义类型

        • 类类型的对象之间也可以隐式转换,需要相应的构造函数支持。

(三)实现例

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class A
{
public:// 使用构造函数explicit就不再支持隐式类型转换// explicit A(int a1)A(int a1)//普通构造:_a1(a1){}//explicit A(int a1, int a2)A(int a1, int a2)//普通构造:_a1(a1), _a2(a2){}void Print(){cout << _a1 << " " << _a2 << endl;}int Get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 2;
};class B
{
public:B(const A& a):_b(a.Get()){}
private:int _b = 0;
};int main()
{A aa1 = 1;aa1.Print();// 使用1构造一个A的临时对象,再用这个临时对象拷贝构造aa1// 编译器遇到连续的【构造+拷贝构造】->优化为直接构造const A& aa2 = 1;//使用const检测是否是先使用1构造一个临时对象,因为临时对象具有常性A aa3 = { 2,2 };// C++11之后才支持多参数转化(使用大括号)// aa3隐式类型转换为b对象// 原理跟上面类似(传两个参数进行构造创建临时对象,再把临时对象拷贝构造给aa3)B b = aa3;// 类类型之间的转化过程也和上面的类似// 使用aa3构造一个B的临时对象,再用这个临时对象拷贝构造bconst B& rb = aa3;//使用const检测是否是先使用aa3构造一个临时对象,因为临时对象具有常性return 0;
}

(四)总结

        ① 内置类型到自定义类型的转化过程:先构造成临时对象,再拷贝构造,被优化为直接进行构造。

        ② 自定义类型到自定义类型的转化过程:先构造成临时对象,再拷贝构造,被优化为直接进行构造。

        ③ 多参数转化需要加大括号 { }

        ④ 可以使用const 引用进行检测。(因为类型转化后是临时变量,有常性)

       

三、静态成员

(一)静态成员的特点

        • static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类里面进行声明,在类外进行初始化(原因如下点所示)。

        • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。(可以理解为把全局的静态变量放在类中,变成类的专属且受类域的限制

        • static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针

        • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的成员变量,因为没有this指针。

        • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数

        • 突破类域就可以访问静态成员,可以通过【类名::静态成员 】或者【对象.静态成员】来访问静态成员变量和静态成员函数。

        • 静态成员也是类的成员,受public、protected、private 访问限定符的限制。

        • 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。

(二)使用例

#define _CRT_SECURE_NO_WARNINGS 1// 实现⼀个类,计算程序中创建出了多少个类对象?
#include<iostream>
using namespace std;
class A
{
public:A()//默认构造{++_scount;}A(const A& t)//拷贝构造{++_scount;}~A()//析构{--_scount;}static int GetACount(){return _scount;}
private:// 类里面声明static int _scount;
};
// 类外面初始化
int A::_scount = 0;int main()
{cout << A::GetACount() << endl;//0A a1, a2;A a3(a1);cout << A::GetACount() << endl;//3cout << a1.GetACount() << endl;//3// 编译报错:error C2248: “A::_scount”: 无法访问 private 成员(在“A”类中声明,受A类的影响)//cout << A::_scount << endl;return 0;
}

        scount是全局的静态变量,每次构造或拷贝构造都让scount++,所以打印出来的结果是0,3,3。

(三)练习题目

1、题目一

题目答案代码:

class Sum
{
public:Sum(){_rel += _num;_num++;}static int get_rel(){return _rel;}private:static int _rel;static int _num;
};int Sum::_rel = 0;
int Sum::_num = 1;class Solution {
public:int Sum_Solution(int n) {Sum arr[n];return Sum::get_rel();}
};

        题目思路:

        因为限制条件的原因,剩下连续创建的方法就是数组,而类类型在定义时会自动调用构造函数,那么在构造函数中完成加法;此时需要数据连续的储存,就使用静态变量来声明与初始化,又因为静态变量受到类的限制,需要提供一个可以获得其值的函数,该函数可以使用静态函数来写,这样可以随时调用,而不需要具体的某个对象。

2、题目二

        设已经有A,B,C,D 4个类的定义:

        程序中A,B,C,D构造函数调用顺序为?

        析构函数调用顺序为?

C c;
int main()
{A a;B b;static D d;return 0;
}

        答:

                构造顺序:c a b d,顺序调用

                析构顺序:b a d c,先调用的后析构,先局部后静态再到全局。

四、友元

(一)友元的特点

        • 友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数和友元类在函数声明或者类声明的前面加friend,并且把友元声明放到一个类的里面。

        • 外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明,他不是类的成员函数。

        • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。

        • 一个函数可以是多个类的友元函数。

        • 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另一个类中的私有和保护成员。

        • 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。

        • 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。

        • 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用

(二)使用例

1、友元函数

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
using namespace std;
// 前置声明,都则A的友元函数声明编译器不认识B
class B;
class A
{// 友元声明friend void func(const A& aa, const B& bb);
private:int _a1 = 1;int _a2 = 2;
};
class B
{// 友元声明friend void func(const A& aa, const B& bb);
private:int _b1 = 3;int _b2 = 4;
};
void func(const A& aa, const B& bb)
{cout << aa._a1 << endl;cout << bb._b1 << endl;
}
int main()
{A aa;B bb;func(aa, bb);return 0;
}

        注意:一个函数可以是多个类的友元函数,不过要让后面的类在前一个类中作友元声明,这样编译器才认识友元函数中的多个类的成员变量。

2、友元类

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{// 友元声明friend class B;
private:int _a1 = 1;int _a2 = 2;
};
class B
{
public:void func1(const A& aa){cout << aa._a1 << endl;cout << _b1 << endl;}void func2(const A& aa){cout << aa._a2 << endl;cout << _b2 << endl;}
private:int _b1 = 3;int _b2 = 4;
};
int main()
{A aa;B bb;bb.func1(aa);bb.func1(aa);return 0;
}

五、内部类

(一)内部类特点

        • 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制(与静态成员类似),所以外部类定义的对象中不包含内部类(并不是外部类的成员)。

        • 内部类默认是外部类的友元类。

        • 内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到 private / protected 位置,那么A类就是B类的专属内部类,其他地方都用不了。

(二)代码实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
private:static int _k;int _h = 1;
public:class B // B默认就是A的友元{public:void foo(const A& a){cout << _k << endl; //OKcout << a._h << endl; //OK}};
};
int A::_k = 1;
int main()
{cout << sizeof(A) << endl;A::B b;A aa;b.foo(aa);return 0;
}

        注意:这种用法用的比较少。

六、匿名对象

(一)匿名对象特点

        • 用【类型(实参) 定义出来的对象叫做匿名对象,相比之前我们定义的 【类型 对象名(实参) 】定义出来的叫有名对象。

        • 匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。

(二)使用例

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};
int main()
{A aa1;// 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义// A aa1();// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,// 但是他的⽣命周期只有这一行,我们可以看到下一行他就会自动调用析构函数A();A(1);A aa2(2);// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景,这个我们以后遇到了再说Solution().Sum_Solution(10);return 0;
}

(三)总结

        ① 匿名对象实例化时无参也要加括号。

        ② 类似于一次性用品。

        ③ 在函数中参数为类类型且需要给缺省值那么可以使用匿名对象。

void Fun(A aa = A(1))
{//业务代码
}

        ④ 引用匿名对象需要使用const,因为临时对象具有常性;被引用后会延长其生命周期,生命周期看aa对象。

const A& aa = A();

七、编译器优化

        • 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传返回值的过程中可以省略的拷贝。

        • 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新一点的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译器还会进行跨行跨表达式的合并优化。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
public:A(int a = 0):_a1(a){cout << "A(int a)" << endl;}A(const A& aa):_a1(aa._a1){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a1 = aa._a1;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a1 = 1;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;//构造f1(aa1);//传参需要拷贝构造cout << endl;// 隐式类型,连续构造+拷贝构造 -> 优化为直接构造f1(1);//1构造为临时的A对象,传参需要拷贝构造 -> 优化为直接构造f1(A(2));//构造一个匿名对象,传参需要拷贝构造 -> 优化为直接构造cout << endl;// 一个表达式中,连续构造+拷贝构造->优化为一个构造cout << "***********************************************" << endl;f2();//返回值拷贝构造给一个临时对象,临时对象再拷贝构造给接收值(vs2019)cout << endl;// 传值返回// 返回时一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造 (vs2019 debug)// 一些编译器会优化得更厉害,进行跨行合并优化,直接变为构造。(vs2022 debug)A aa2 = f2();//返回值拷贝构造给一个临时对象,临时对象再拷贝构造给接收值(vs2019)cout << endl;// 返回时一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造 (vs2019 debug)// 一些编译器会优化得更厉害,进行跨行合并优化,直接变为构造。(vs2022 debug)aa1 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化return 0;}

        以上内容仅供分享,若有错误,请多指正。

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

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

相关文章

【芯片设计】DC综合retiming策略的学习与实践

对于DC综合中的retiming策略早有耳闻&#xff0c;但是一直没有比较系统的学习和实验过&#xff0c;正好借着这次交付过程的归纳总结机会&#xff0c;把一些零零散散的收获学习记录下。 记得刚出新手村时和某位大佬聊到过&#xff0c;他说你逻辑里写了在某级计算一个结果&#…

UE5之5.4 第一人称示例代码阅读2 子弹发射逻辑

TP_WeaponComponent.h 看看头文件 暴露了attach weapon和fire给蓝图 这两个函数意义一看名字吧&#xff0c;就是捡起来枪的时候执行&#xff0c;一个就是发射子弹的时候执行 #pragma once#include "CoreMinimal.h" #include "Components/SkeletalMeshComponen…

Appium中的api(二)

目录 元素定位操作api 1--通过id定位api 2--通过class获取定位元素 3--通过xpath表达式定位元素 4.完整代码 解释 效果 元素定位操作api 1--通过id定位api 注:driver.find_element是获取单个元素 # 通过id获取 mySearchId "com.android.settings:id/search_acti…

如何对pdf文件进行加密?pdf文件加密全攻略与深度解析(5个方法)

如何对pdf文件进行加密&#xff1f; 只见&#xff0c;在深夜的情报局里&#xff0c;特工小李将一份绝密PDF文件放在保险箱内&#xff0c;以为这样就天衣无缝了。 细细推敲&#xff0c;漏洞百出&#xff1a; 如果钥匙被盗呢&#xff1f;如果被神匠破解出密码呢&#xff1f;如果…

Halcon基础-瓶盖带角度的OCR批量识别

Halcon基础-OCR识别 1、OCR识别素材2、创建路径文件3、Halcon代码实现4、运行效果5、资源获取 1、OCR识别素材 这里我准备了7张不同角度的OCR图片&#xff0c;如下所示&#xff1a; 2、创建路径文件 按照下图所示创建全部文件夹和文件&#xff1a; 01用来存放OCR识别原图 c…

Vue中使用el-upload实现文件上传时控制提交按钮状态的最佳实践

在Web应用开发中&#xff0c;文件上传是一个常见的需求。在使用Vue框架和Element UI库时&#xff0c;我们经常使用el-upload组件来处理文件上传。但是&#xff0c;如何在上传过程中控制提交按钮的可用状态&#xff0c;以避免在上传未完成时误触提交操作&#xff0c;是一个值得探…

解决:如何在opencv中得到与matlab立体标定一样的矫正图?(python版opencv)

目的&#xff1a;采用一样的标定参数&#xff0c;matlab中和opencv中的立体矫正图像是一样的吗&#xff1f;不一样的话怎么让它们一样&#xff1f; 结论&#xff1a;不一样。后文为解决方案。 原因&#xff1a;注意matlab的标定结果在matlab中的用法和在opencv中的用法不一样&a…

光伏电站折旧率的计算

折旧率的计算方法 直线法&#xff1a;直线法是最常用的折旧计算方法。它假设光伏设备在使用寿命内每年的折旧额保持不变。计算公式为&#xff1a; 折旧率(资产原值-净残值)预计使用寿命。 其中&#xff0c;资产原值是指光伏设备购置价值或建成投产时的价值&#xff1b;净残值…

chrome清除https状态

莫名其妙的http跳转到https的url了。 解决办法 浏览器地址栏输入&#xff1a;chrome://net-internals/#hsts 输入你需要删除的域名即可&#xff01;&#xff01;&#xff01;

AMD平台,5600X+6650XT,虚拟机安装macOS 15 Sequoia 15.0.1 (2024.10)

macOS 15 Sequoia终于出正式版了&#xff0c;没有Mac&#xff0c;所以还是虚拟机玩玩&#xff0c;还是属于折腾&#xff0c;安装过程和之前差不多&#xff0c;这次我从外网获得了8核和16核openCore&#xff0c;分享一下。 提前发一下ISO镜像地址和openCore引导磁盘地址 ISO镜…

《人工智能往事》—— 简而言之,AI 已经包围了我们。AI 就是我们。

《人工智能往事》这本书我挺喜欢的&#xff08;推荐给对计算机和AI史有考古兴趣的同学们&#xff09;。我是几年前读的英文版《This Could Be Important: My Life and Times with the Artificial Intelligentsia Pamela McCorduck》很高兴发现国内推出了译本。 作者帕梅拉麦考…

一座数智工厂,看见汽车制造的诗与远方

今天的中国&#xff0c;已经是名副其实的汽车制造与出口大国。 根据国家统计局10月18日发布的数据&#xff0c;今年9月中国新能源汽车产量同比增长48.5%&#xff0c;增速为2023年5月以来新高。1月至9月汽车行业出口交货值同比增长17.1%。中国汽车产业的高速发展&#xff0c;离不…

学习docker第三弹------Docker镜像以及推送拉取镜像到阿里云公有仓库和私有仓库

docker目录 1 Docker镜像dockers镜像的进一步理解 2 Docker镜像commit操作实例案例内容是ubuntu安装vim 3 将本地镜像推送至阿里云4 将阿里云镜像下载到本地仓库5 后记 1 Docker镜像 镜像&#xff0c;是docker的三件套之一&#xff08;镜像、容器、仓库&#xff09;&#xff0…

uniapp微信小程序使用vant组件库

1. vant组件库(微信小程序版本)官网地址 地址: vant组件库(微信小程序版本) 2. uniapp微信小程序引入 <1>. 去到GitHub中将资源克隆到本地,地址: vant-weapp <2>. 到本地把文件拷贝到我们的uniapp微信小程序项目中 在项目的目录下新建一个文件wxcomponents&#…

iOS 18.2开发者预览版 Beta 1版本发布,欧盟允许卸载应用商店

苹果今天为开发人员推送了iOS 18.2开发者预览版 Beta 1版本 更新&#xff08;内部版本号&#xff1a;22C5109p&#xff09;&#xff0c;本次更新距离上次发布 Beta / RC 间隔 2 天。该版本仅适用于支持Apple Intelligence的设备&#xff0c;包括iPhone 15 Pro系列和iPhone 16系…

Spring Web MVC 入门

1. 什么是 Spring Web MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从从⼀开始就包含在Spring框架中。它的 正式名称“SpringWebMVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC". 什么是Servlet呢? Ser…

开拓鸿蒙测试新境界,龙测科技引领自动化测试未来

在当今科技舞台上&#xff0c;鸿蒙 OS 以非凡先进性强势登场&#xff0c;打破传统操作系统格局&#xff0c;为软件测试领域带来全新机遇与艰巨挑战。 一、鸿蒙 OS 的辉煌崛起 &#xff08;一&#xff09;壮丽发展历程与卓越市场地位 鸿蒙 OS 的发展如波澜壮阔的史诗。2023 年…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十二)拓展图优化库g2o(一)框架

【转载】理解图优化&#xff0c;一步步带你看懂g2o框架 文章来源&#xff1a;理解图优化&#xff0c;一步步带你看懂g2o框架 小白&#xff1a;师兄师兄&#xff0c;最近我在看SLAM的优化算法&#xff0c;有种方法叫“图优化”&#xff0c;以前学习算法的时候还有一个优化方法…

Python量化交易(二):金融市场的基础概念

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月学习赛的Python量化交易学习总结文档&#xff1b;在现代社会中&#xff0c;投资已成为个人、机构和政府追求财富增长和资源配置的重要方式。…

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

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