C++:类和对象(下)
文章目录
- 1 再谈构造函数
- 1.1 构造函数体赋值
- 1.2 初始化列表
- 1.3 explicit关键字
- 2 static成员
- 2.1 概念
- 2.2 特性
- 3 友元
- 3.1 友元函数(流插入(<<)及流提取(>>)运算符重载)
- 3.2 友元类
- 4 内部类
- 5 匿名对象
- 6 拷贝对象时的一些编译器优化
- 7 再次理解类和对象
1 再谈构造函数
1.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 初始化列表
前言:
我们知道,当我们编写一个类时,只是对这个类整体进行了一个声明,只有当我们通过类的实例化创建出该类类型对象,才算是完成一个对象的定义,但实际上,这只能算是对对象整体的定义,那其中的每个成员变量又是在什么时候定义的呢?如下以一个类为例,这里类中没有主动编写的构造函数,在定义对象时调用编译器默认生成的构造函数。问题来了,当我们在类中增加const成员变量后,再运行程序会发现编译错误,原因是作为内置类型成员变量,编译器默认生成的构造函数不会对其进行处理,而const修饰的变量必须在定义的时候初始化(注意,在C++98时还不能在成员变量声明时给缺省值),此时直接定义对象,const成员变量没有实现初始化,因此会发生编译报错。
class A {
private:int _a1;int _a2;//const int _x; //const变量必须在定义的时候初始化//const int _x = 0; //C++98不支持缺省值
};int main() {A aa; //对象整体的定义,每个成员变量什么时候定义?return 0;
}
为了解决成员变量初始化的问题,C++引入了初始化列表的概念。
初始化列表:以一个
冒号:
开始,接着是一个以逗号分割的数据成员列表,每个成员变量后面跟一个放在括号()
中的初始值或表达式。
我们可以理解为初始化列表是调用该构造函数的对象的每个成员变量定义的地方。
示例:
class Date{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};
初始化列表的相关注意事项:
-
拷贝构造函数也有初始化列表。
-
每个成员变量在初始化列表中只能出现一次(换句话说,初始化只能初始一次)。如果某个成员变量没有在初始化列表中,则再使用声明时的缺省值进行初始化,如果缺省值也没有,则以随机值初始化。
-
类中如果包含以下成员,必须放在初始化列表位置进行初始化:
- 引用成员变量(必须在定义时进行初始化)
- const成员变量(必须在定义时进行初始化)
- 没有默认构造函数的自定义类型成员
示例:
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
};
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,类中每个成员变量都会先使用初始化列表进行初始化。对于内置类型成员变量,如果没有显示使用初始化列表,则以缺省值进行初始化,如果缺省值也没有,则以随机值初始化;对于自定义类型成员,如果显示使用了初始化列表,则调用其对应构造函数,如果没有显示使用初始化列表,则调用其默认构造函数,如果默认构造函数也没有,则不能完成初始化,也就不能通过编译 。
示例:
class Time{
public:Time(int hour = 0):_hour(hour){cout << "Time()" << endl;}private:int _hour;
};class Date{
public:Date(int day){}private:int _day;Time _t;
};int main()
{Date d(1);
}
//输出:Time()
- 成员变量在类中的声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
class A{
public:A(int a):_a1(a) //先定义_a1, _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}private:int _a2; //先声明_a2int _a1;
};int main() {A aa(1);aa.Print();
}//输出:1 -858993460
//即按声明顺序进行初始化,在_a1在_a2之后初始化,而_a2又以_a1的值进行初始化,此时_a1还是随机值,所以_a2为随机值
1.3 explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值而其余参数均有默认值的构造函数,还可以进行隐式类型转换。而如果不想使其能进行隐式类型转换,可以用关键字
explicit
修饰构造函数。
示例:
class A {
public://单参构造函数 - 支持隐式类型转换A(int a):_a1(a){cout << "A(int a)" << endl;}不支持隐式类型转换//explicit A(int a)// :_a1(a)//{// cout << "A(int a)" << endl;//}//多参构造函数 - C++98不支持隐式类型转换,C++11可以以{参数……}的方式支持A(int a1, int a2):_a1(a1),_a2(a2){}不支持隐式类型转换//explicit A(int a1, int a2)// :_a1(a1)// , _a2(a2)//{}A(const A& aa) :_a1(aa._a1){cout << "A(const A& aa)" << endl;}private:int _a2;int _a1;
};int main() {A aa1(1); //单参构造函数//下面语句发生了隐式类型转换:通过创建一个临时变量将1转换成A类类型对象,再用临时的对象拷贝创建aa2对象//按理来说,运行程序,下面语句会调用一次构造函数加一次拷贝构造函数,//但实际输出表示只调用了一次构造函数,这是因为编译器进行了优化,直接用1构造了aa2对象A aa2 = 1; //下面语句如果不加const,则无法通过编译,而加了const则编译通过,//正是因为隐式类型转换产生了临时对象,而临时对象具有常属性,//因此需要用const修饰才能进行引用,这也侧面说明了隐式类型转换的过程中产生了临时变量const A& ref = 2;A aa3(1, 2);//多参构造函数A aa4 = { 1, 2 };//隐式类型转换 - C++11支持,C++98不支持return 0;
}
2 static成员
2.1 概念
声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称之为静态成员变量;用 static 修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
示例:要求实现一个类,计算程序中创建出了多少个类对象。
① 方法一:使用全局变量计数
错误示例:
#include <iostream>using namespace std;int count = 0;class A {
public://创建对象要么使用构造函数,要么使用拷贝构造函数A() { ++count; } //只要调用构造函数就让计数值加一A(const A& t) { ++count; } //调用拷贝构造函数也让计数值加一~A() { --count; } //如果对象被析构,则计数值减一
};int main() {cout << count << endl;A a1, a2;A a3(a1);cout << count << endl;return 0;
}
上述代码运行后报错,指出count是不明确的符号,这是因为在C++的 xutility(5263,45)
文件中有个与 count 的同名函数 std::count(const _InIt,const _InIt,const _Ty &)
,而我们选择将整个 std 命名空间展开,这就造成了命名冲突。基于此,可以做出以下修改:只将用到 cout 及 endl 展开。
正确写法:
#include <iostream>
using std::cout;
using std::endl;int count = 0;class A {
public://创建对象要么使用构造函数,要么使用拷贝构造函数A() { ++count; } //只要调用构造函数就让计数值加一A(const A& t) { ++count; } //调用拷贝构造函数也让计数值加一~A() { --count; } //如果对象被析构,则计数值减一
};int main() {cout << count << endl;A a1, a2;A a3(a1);cout << count << endl;return 0;
}
可以看到,使用这种方法统计创建的对象要稍微复杂一些,且因为全局变量可以在任意位置被修改,所以存在安全隐患。
② 方法二:使用静态成员变量计数
#include <iostream>using namespace std;class A{
public://创建对象要么使用构造函数,要么使用拷贝构造函数A() { ++_scount; } //只要调用构造函数就让计数值加一A(const A & t) { ++_scount; } //调用拷贝构造函数也让计数值加一~A() { --_scount; } //如果对象被析构,则计数值减一//受访问限定符限制,为了保证封装性,提供GetACount()函数来获取静态成员变量值//静态成员函数static int GetACount1() { return _scount; }//非静态成员函数也可以调用静态成员函数int GetACount2() { return A::GetACount1(); }//静态成员函数只有在包含类类型对象参数时,才能用对象调用非静态成员函数static int GetACount3(A& a) { return a.GetACount2(); }private:static int _scount;//静态成员变量
};int A::_scount = 0;//受类域限制,需以 类名:: 的方式访问int main(){cout << A::GetACount1() << endl; // 类名::静态成员方式调用A a1, a2;A a3(a1);cout << a3.GetACount1() << endl; // 对象.静态成员方式调用A a4[10];//对象数组cout << a3.GetACount2() << endl;//非静态成员函数调用静态成员函数cout << A::GetACount3(a3) << endl;//静态成员函数调用非静态成员函数return 0;
}//输出:0 3 13 13
2.2 特性
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
- 静态成员变量必须在类外定义,定义时不添加 static 关键字,类中只是声明。
- 类静态成员即可用
类名::静态成员
或者对象.静态成员
的方式访问。 - 静态成员函数没有隐藏的 this指针,不能访问任何非静态成员。
- 静态成员也是类的成员,受public、protected、private访问限定符的限制。
- 非静态成员函数可以调用静态成员函数,静态成员函数只有在包含类类型对象参数时采用通过对象调用非静态成员函数。
3 友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不建议过多使用。
友元分为:友元函数和友元类
3.1 友元函数(流插入(<<)及流提取(>>)运算符重载)
以下以实现对 流插入运算符>>
和 流提取运算符<<
重载为例说明友元函数使用:
以日期类为例,可以看到,当我们想输出日期时,通常时会先编写一个成员函数,然后通过对象去调用成员函数来输出相应的年、月、日。我们知道,在C++中通常使用 cin >>
和 cout <<
进行内置类型的输入输出,那能不能也使用这种方式来对自定义类型对象进行输入输出呢?答案是当然可以。
通过 cplusplus 网站查看,可以发现,实际上 cout
和 cin
分别是 ostream
和 istream
类型的对象,而之所以在C++中 cin >>
和 cout <<
输入输出可以自动识别类型,是因为在 istream
和 ostream
类中分别实现了的对 流提取运算符 >>
和 流插入运算符 <<
的重载。也就是说,如果我们也能实现对这两个运算符的重载,那就可以采用 cin >>
和 cout <<
的方式进行自定义类型对象的输入输出了。
但这里需要注意的是,该运算符重载是实现在 istream
和 ostream
这两个类中的,而这两个类是无法被修改的,因此我们只能选择在全局实现这两个运算符的重载,或是在需要用到的该运算符的自己编写的类中进行运算符重载。
考虑到为了能访问对象中的私有成员,我们通常会将运算符重载实现在对应的类中,如下:
class Date{
public:Date(int year = 2023, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void operator<<(ostream& out) {out << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main() {Date d1(2023, 2, 1);//cout << d1; //编译报错d1 << cout; //输出2023-2-1d1.operator<<(cout); //输出2023-2-1return 0;
}
但运行程序发现:我们采用 cout << d1;
的方式输出日期时会发生编译报错,而采用 d1 << cout;
或 d1.operator<<(cout);
的方式却可以正常输出。这是因为当我们在日期类中实现运算符重载时,默认第一个参数即为隐含参数 *this
,而对于双目操作符来说,第一个参数即为左操作数。但是这样的输出方式与我们平时的输出写法有所差异,那怎么能采用 cout << d1;
的方式进行输出呢?
于是我们考虑将运算符重载实现在类外,这样我们就可以主动使 ostream
类对象作为第一个参数,而日期类对象为第二个参数。但这样还面临一个问题,我们无法在类外访问私有成员,当然,我们也可以将成员变为公有,但这会失去封装性,一般不建议这样处理;此外,也可以通过设置对应的 Get_year()
等公有成员函数来在类外获取私有成员;而还有一种方法则是使用 friend
修饰函数(即友元函数),可以理解为经过修饰后该函数成为了对应类的朋友,因此可以访问类中私有成员。此外,还有一点需要注意,我们平常使用的流插入运算符是可以连续使用的,也就是说,还运算符重载应该要有返回值,返回 ostream
类型对象的引用。如下所示:
class Date{//友元函数声明friend ostream& operator<<(ostream& out, const Date& date);public:Date(int year = 2023, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//void operator<<(ostream& out) {// out << _year << "-" << _month << "-" << _day << endl;//}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& date) {out << date._year << "-" << date._month << "-" << date._day << endl;return out;
}int main() {Date d1(2023, 2, 1);Date d2(2023, 2, 7);cout << d1 << d2; //输出://2023-2-1//2023-2-7return 0;
}
同样的,接下来我们也可以实现流提取运算符重载如下:
class{friend istream& operator>>(istream& in, Date& date);
public://其它方法
private:int _year;int _month;int _day;
};istream& operator>>(istream& in, Date& date) {in >> date._year >> date._month >> date._day;return in;
}int main() {Date d1;cin >> d1;cout << d1;return 0;
}
说明:
- 友元函数可以直接访问类的私有和保护成员,但它不是类的成员函数,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加
friend
关键字。 - 友元函数不能用
const
修饰。因为 const 只能修饰成员函数,更直接的说 const 是用来修饰 this指针 的,而友元函数没有 this指针。 - 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
- 一个函数可以是多个类的友元函数。
- 友元函数的调用与普通函数的调用原理相同。
3.2 友元类
- 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
- 友元关系是单向的,不具有交换性。
如下,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类中的私有成员变量,但想在 Time 类中访问 Date 类中的私有成员变量则不行。
class Time{friend class Date; //声明日期类为时间类的友元类,则在日期类中就可直接访问Time类中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};class Date{
public:Date(int year = 2023, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){//直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};
- 友元关系不能传递。 (如果 C 是 B 的友元,B 是 A 的友元,也不能说明 C 是 A 的友元。)
- 友元关系不能继承。
4 内部类
概念:如果一个类定义在另一个类的内部,这个类就叫做内部类。 内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越访问权限。
注意:内部类就是外部类的友元类。 内部类可以通过外部类的对象参数来访问外部类中的所有成员。但外部类不是内部类的友元。
特性:
- 内部类可以定义在外部类的public、protected、private任意位置。
- 内部类可以直接访问外部类中的 static 成员,不需要外部类的对象/类名。
sizeof(外部类) = 外部类
,和内部类没有任何关系。
示例:
class A {
private:static int k;int h;public:class B { // B天生就是A的友元private:int _b = 2;public:void foo(const A& a) {cout << k << endl;//OKcout << a.h << endl;//OK}};
};int A::k = 1;int main() {A::B b;b.foo(A());cout << sizeof(A) << endl; //输出:4,其中静态成员变量存储在静态区return 0;
}
5 匿名对象
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 aa2(2);// 匿名对象在这样场景下就很好用Solution().Sum_Solution(10);return 0;
}
输出结果:
6 拷贝对象时的一些编译器优化
在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,在一些场景下还是非常有用的。
示例:
class A
{
public://构造函数A(int a = 0):_a(a){cout << "A(int a)" << endl;}//拷贝构造函数A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}//赋值运算符重载A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}private:int _a;
};void f1(A aa)
{}A f2(){A aa;return aa;
}int main(){// 传值传参A aa1;f1(aa1);cout << endl;// 传值返回f2();cout << endl;// 隐式类型,连续构造+拷贝构造->优化为直接构造f1(1);// 一个表达式中,连续构造+拷贝构造->优化为一个构造f1(A(2));cout << endl;// 一个表达式中,连续拷贝构造+拷贝构造->优化为一个拷贝构造A aa2 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化aa1 = f2();cout << endl;return 0;
}
结果输出:
说明: 不同的编译器的优化程度不同,从上述结果也可以看出,本文中所使用的VS2022的编译器的优化程度比较大。对于函数 f2 来说,不优化的情况下应该是调用一个构造函数和一个拷贝构造函数,而这里直接优化成了一次构造,显然优化方式稍有些激进,因为函数 f2 中的对象构造和返回是分开的,为了避免中间可能还有使用对象的地方,保守些的编译器在此是不做优化的。
总结:
- 关于对象返回的总结:
- 接收返回值对象时,尽量使用拷贝构造方式接收,不要赋值接收;
- 函数中返回对象时,尽量返回匿名对象。
- 关于函数传参的总结:
- 尽量使用
const 类型&
的方式传参。
- 尽量使用
7 再次理解类和对象
现实生活中的实体,计算机并不认识,计算机只认识二进制格式的数据。如果想要让计算机认识现实生活中的实体,用户必须通过某种面向对象的语言,对实体进行描述,然后通过编写程序,创建对象后计算机才可以认识。比如想要让计算机认识洗衣机,就需要:
- 用户先要对现实中洗衣机实体进行抽象 – 即在人为思想层面对洗衣机进行认识,洗衣机有什么属性,有哪些功能,即对洗衣机进行抽象认知的一个过程。
- 经过上述步骤后,在人的头脑中已经对洗衣机有了一个清晰的认识,只不过此时计算机还不清楚,想要让计算机识别人想象中的洗衣机,就需要人通过某种面向对象的语言(比如:C++、Java、Python等)将洗衣机用类来进行描述,并输入到计算机中。
- 经过上述步骤后,计算机中就有了一个洗衣机类,但洗衣机类只是站在计算机的角度对洗衣机对象进行描述的,通过洗衣机类,可以实例化出一个个具体的洗衣机对象,此时计算机才能清楚洗衣机是什么东西。
- 接着用户就可以借助计算机中的洗衣机对象,来模拟现实中的洗衣机实体了。
注意:类是对某一实体(对象)来进行描述的,描述该对象具有哪些属性,哪些方法,描述完之后就形成了一种新的自定义类型,使用该自定义类型就可以实例化出具体的对象。
以上是我对C++中类和对象相关知识的一些学习记录总结,如有错误,希望大家帮忙指正,也欢迎大家给予建议和讨论,谢谢!
相关文章:

C++:类和对象(下)
文章目录1 再谈构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字2 static成员2.1 概念2.2 特性3 友元3.1 友元函数(流插入(<<)及流提取(>>)运算符重载)3.2 友元类4 内部类5 匿名对…...
ASP.NET Core MVC 项目 AOP之IResultFilter和IAsyncResultFilter
目录 一:说明 二:IActionFilter同步 三:IAsyncActionFilter异步 一:说明 IResultFilter同步过滤器与IAsyncResultFilter异步过滤器常常被用作于渲染视图或处理结果。 IResultFilter同步过滤器执行顺序: 1:执行控制器中的构造函数,实例化控制器 2:执行具体的Acti…...

jstack排查cpu占用高[复习]
这样就可以看到占用CPU高的代码位置。 总结:就是先查到占用高的应用和具体的线程,然后根据线程到堆积信息查找即可。 不过堆栈信息非十进制,需提前把线程号转为十六进制。 这样就可以看到占用CPU高的代码位置。 总结:就是先查到…...

网络安全-Pyhton环境搭建
网络安全-Pyhton环境搭建 https://www.kali.org/get-kali/#kali-installer-images—kali官网下载地址 python这个东东呢 是目前来说最简单,方便的开源的脚本语言 广泛用于Web开发,AI,网站开发等领域 python要装2和3 为什么要安装两个版本…...

SpringBoot Mybatis 分页实战
pageInfo的属性 pageNum:当前页 pageSize:页面数据量 startRow:当前页首条数据为总数据的第几条 endRow:当前页最后一条数据为总数据的第几条 total:总数据量 pages:总页面数 listPage{}结果集 reasonable …...

计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性
计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性 Feasibility of Simultaneous Computed Tomographic Colonography and Fully Automated Bone Mineral Densitometry in a Single Examination 简单总结: 数据:患者的结肠镜检查和腹部CT检查…...

Java多级缓存是为了解决什么的?
前言 提到缓存,想必每一位软件工程师都不陌生,它是目前架构设计中提高性能最直接的方式。 缓存技术存在于应用场景的方方面面。从网站提高性能的角度分析,缓存可以放在浏览器,可以放在反向代理服务器,还可以放…...

MongoDB--》索引的了解及具体操作
目录 索引—index 索引的类型 索引的管理操作 索引的使用 索引—index 使用索引的原因:索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这…...

Python open()函数详解:打开指定文件
在 Python 中,如果想要操作文件,首先需要创建或者打开指定的文件,并创建一个文件对象,而这些工作可以通过内置的 open() 函数实现。open() 函数用于创建或打开指定文件,该函数的常用语法格式如下:file ope…...

CentOS Stream 9尝鲜安装教程
作者:IT圈黎俊杰 一、下载CentOS Stream 9安装介质 在CentOS官网可以下载到CentOS Stream 9的安装介质,正面列出ISO介质的下载链接地址: https://download.cf.centos.org/9-stream/BaseOS/x86_64/iso/CentOS-Stream-9-20221019.0-x86_64-dv…...

Ambire AdEx 2023 年路线图
Ambire AdEx 是为简化 web3 显示广告而建立的,领先于时代。到 2023 年,它将专注于服务用户需求,同时保持其作为区块链隐私解决方案的核心,反对传统的数字广告模式。 回顾 2022 年 2022 年,AdEx 网络处理了超过 1 亿次展…...

两种特征提取方法与深度学习方法对比的小型金属物体分类分析研究
本文讨论了用于对包括螺丝、螺母、钥匙和硬币在内的小型金属物体进行分类的两种特征提取方法的效率:定向梯度直方图 (HOG) 和局部二进制模式 (LBP)。首先提取标记图像的所需特征并以特征矩阵的形式保存。使用三种不同的分类方法(非参数 K 最近邻算法、支…...

传奇私服搭建网站的几种方法
搭建网站的几种方法:一些人,连简单的搭建网站都不会,还要请技术帮忙,真是牛B,这里简单介绍下几种办法一:2003系统下,直接使用IIS,这个太简单了,桌面上就有IIS,…...
i.MX8MP平台开发分享(clock篇)- 各类clock的注册
专栏目录:专栏目录传送门 平台内核i.MX8MP5.15.71文章目录 1、关键数据结构1.1 clk_hw1.2 clk_hw_onecell_data2.一个clk的注册过程2.1 fixed clk2.2 pll14xx2.3 fixed factor2.4 mux2.5 composite2.6 gate1、关键数据结构 1.1 clk_hw clk_hw是描述一个时钟信息的最小单元。…...

java ssm计算机系统在线考试平台idea
本系统主要包括以下功能模块学生、教师、班级、考试评阅、在线考试、试题内容、考试等模块,通过这些模块的实现能够基本满足日常计算机系统平台的操作。 本文着重阐述了计算机系统平台的分析、设计与实现,首先介绍开发系统和环境配置、数据库的设计&…...

C语言(字符串函数)
这章的内容记得引用<string.h>头文件 目录 1.strlen() 2.strcat() 3.strncat() 4.strcmp() 5.strncmp() 6.strcpy() 7.strncpy() 8.sprintf() 8.strchr() 9.strpbrk() 10.strrchr() 11.strstr() 1.strlen() 用于统计字符串的…...

Maxwell工作流程详解
要介绍maxwell的工作原理,首先需要讲一下mysql主从复制的原理 mysql主从复制原理: 如上图,左边是master主节点,右边是slave从节点 工作流程: 1.往主节点mysql的数据库中写入数据,产生数据变化,…...

13- EM算法与GMM高斯混合 (聚类算法) (算法)
最大期望算法(EM算法) ,曾入选“数据挖掘十大算法”中,是最常见的隐变量估计方法,在机器学习中有极为广泛的用途,例如常被用来学习高斯混合模型的参数。EM算法是在概率模型中寻找参数最大似然估计或者最大后验估计的算法ÿ…...
【新】华为OD机试 - 二叉树层次遍历(Python)| 刷完获取OD招聘渠道
二叉树层次遍历 题目 有一棵二叉树 每一个节点用一个大写字母标识 最多26个节点 现有两组字母 分别表示后序遍历(左孩子指向右孩子指向父节点) 和中序遍历(左孩子指向父节点指向右孩子) 请输出层次遍历的结果 输入 输入为两个字符串 分别为二叉树的后序遍历和中序遍历结…...

工作记录------@Accessors(chain = true)引起的BUG,Excel导入时获取不到值
工作记录------Accessors(chain true)引起的BUG,Excel导入时获取不到值 如题所示 背景:在进行文件excel文件导入时,发现实体类获取到的属性值都为null。 框架:com.alibaba.excel 2.2.0的版本。 结论:首先说下结论 如…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...