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

【C++初阶】四、类和对象(下)

文章目录

  • 一、再谈构造函数
    • 构造函数体赋值
    • 初始化列表
    • explicit关键字
  • 二、Static成员
    • 引入- 计算类中创建了多少个类对象
    • 概念
    • 特性
    • 静态成员函数的访问
  • 三、友元
    • 友元函数
    • 友元类
  • 四、内部类
  • 五、匿名对象
  • 六、拷贝对象时的一些编译器优化

一、再谈构造函数

构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量
的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。 因为初始化只能初始
化一次,而构造函数体内可以多次赋值。

class Date
{
public:Date(int year, int month, int day){_year = year;//第一次赋值_year = 2001;//第二次赋值_year = 2022;//第三次赋值//....._month = month;_day = day;}
private:int _year;int _month;int _day;
};

初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式

如以下形式:

class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};

上述是一个简单的日期类构造函数的初始化列表写法,当遇到一个比较复杂的类时,初始化列表和函数体内初始化可以混着来

比如栈:

class Stack
{
public:/*Stack(int capacity = 4):_a((int*)malloc(sizeof(int)*capacity))	//可以在初始化列表写, _top(0), _capacity(capacity){if (_a == nullptr){perror("malloc fail");exit(-1);}}*/// 初始化列表和函数体内初始化可以混着来Stack(int capacity = 4): _top(0), _capacity(capacity){_a = (int*)malloc(sizeof(int) * capacity);	//可以在函数体内写if (_a == nullptr){perror("malloc fail");exit(-1);}memset(_a, 0, sizeof(int) * capacity);}
private:int* _a;  // 声明int _top;int _capacity;
};

我们知道,一个类在没有实例化之前,类中的成员变量都只是声明,而一旦对象实例化出来则是类的整体定义,那对象的每个成员是什么时候定义呢?- - - 初始化列表 (c++的定义,没有为什么)

而类中有以下三种成员变量,必须放在初始化列表位置进行初始化

1. 引用成员变量
我们在学习引用的时候知道,引用类型的变量在定义时就必须给其一个初始值。

int a = 10;
int& b = a;// 创建时就初始化

由于对象的成员是在初始化列表位置定义的,所以我们只能在初始化列表定义引用成员变量

class B
{
public:B(int ref): _ref(ref){}
private:int& _ref;  // 引用
};

2. const成员变量
被const修饰的变量也必须在定义时就给其一个初始值。

const int a = 10;//correct 创建时就初始化
const int b;//error 创建时未初始化

所以也必须使用初始化列表进行初始化。

class B
{
public:B():_n(10){}
private:const int _n; // const 成员变量
};

3. 自定义类型成员(且该类没有默认构造函数时)
若一个类中存在类对象时,且该类对象的类没有默认构造函数。那么我们在实例化该类对象时就需要传参对其进行初始化,所以实例化没有默认构造函数的类对象时必须使用初始化列表对其进行初始化。
在这里再声明一下,默认构造函数是指不用传参就可以调用的构造函数:
 1. 我们不写,编译器自动生成的构造函数。
 2. 无参的构造函数。
 3. 全缺省的构造函数。

class A //该类没有默认构造函数 
{
public:A(int val) //注:这个不叫默认构造函数(需要传参调用){_val = val;}
private:int _val;
};class B
{
public:B():_a(2022) //必须使用初始化列表对其进行初始化{}
private:A _a; //自定义类型成员(该类没有默认构造函数)
};

所以这就是为什么要有初始化列表存在的原因了。

使用初始化列表注意事项:

一、每个成员变量在初始化列表中只能出现一次
 因为初始化只能进行一次,所以同一个成员变量在初始化列表中不能多次出现。

二、类中包含以下成员,必须放在初始化列表位置进行初始化:(在总结一下)

  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)
class A
{
public:A(int val):_val(val){}
private:int _val;
};
class B
{
public:B(int a, int ref):_a(a)//必须在初始化列表传参初始化, _ref(ref), _n(10){}
private:A _a;// 没有默认构造函数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);
}

四、成员变量在类中声明的次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后顺序无关
举个例子:

class A
{
public://由于先声明的是_a2在声明_a1,所以编译器先初始化_a2,在初始化_a1。//而_a1一开始是随机值,所以_a2是随机值,_a1是1A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}
A.输出1  1
B.程序崩溃
C.编译不通过
D.输出1  随机值

在这里插入图片描述

整体总结:

对象每个成员在 初始化列表的时候定义;
每个成员都要走初始化列表,就算不显示在初始化列表写,也会走;
如果在初始化列表显示写了就用显示写的初始化;
如果没有在初始化列表显示初始化:

  1. 在定义时就必须进行初始化的变量类型,就必须放在初始化列表进行初始化。
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)
  1. 内置类型,有缺省值用缺省值,没有就用随机值
  2. 自定义类型,调用默认它的默认构造函数,如果没有默认构造就必须在初始化列表传参初始化,否则就报错。

explicit关键字

一、隐式类型转换:
 实际上,我们早就接触了隐式类型转换(在讲解传值返回和传引用返回中也讲到过),以下代码也叫隐式类型转换:

double d = 1.1;
int i = d;//隐式类型转换

在这里插入图片描述
在这个过程中,编译器会先构建一个int类型的临时变量接收d的值,然后再将该临时变量的值赋值给i。

因为临时变量具有常属性,所以我们若是进行引用的操作时,需要加const,因为这里涉及到了权限的问题(只有指针和引用才会考虑权限的问题)。
在这里插入图片描述

二、explicit关键字介绍

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值
的构造函数,还具有类型转换的作用。

一、单参数或只需传一个参数值:

#include <iostream>
using namespace std;
class Date
{
public:Date(int year = 0) //单个参数的构造函数:_year(year){}// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转换作用//Date(int year, int month = 1, int day = 1)//: _year(year)//, _month(month)//, _day(day)//{}void Print(){cout << _year << endl;}
private:int _year;int _month;int _day;
};
int main()
{//隐式类型转换Date d1 = 2021; //支持该操作d1.Print();return 0;
}

在语法上,代码中Date d1 = 2021等价于以下两句代码:

Date tmp(2021); //先构造
Date d1(tmp); //再拷贝构造

在早期的编译器中,当编译器遇到Date d1 = 2021这句代码时,会先构造一个临时对象,再用临时对象拷贝构造d1;但是现在的编译器已经做了优化,当遇到Date d1 = 2021这句代码时,会按照Date d1(2021)这句代码处理,这就叫做隐式类型转换。

二、多参数构造

class Date
{
public:// 多参数构造//explicit Date(int year, int month, int day)Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};
int main()
{Date d1 = { 2022, 10, 12 };// 等价于Date d2(2022, 10, 12 );const Date& d3 = { 2022, 10, 12 };//引用,必须加const,临时变量具有常属性return 0;
}

**注意:**多参数构造的隐式类型转换是C++11才支持的,C++98不支持,只支持单参数构造的隐式类型转换。

对于Date d1 = 2021这种代码的可读性不是很好,我们若是想禁止单参数构造函数的隐式转换,可以用关键字explicit来修饰构造函数。

class Date {
public:explicit Date(int year): _year(year){}private:int _year;
};

在这里插入图片描述

二、Static成员

引入- 计算类中创建了多少个类对象

如果我们要计算一个类中创建了多少个类对象,我们可以用 count 计算一下

int N = 0;  // 全局变量class A {
public:A(int a = 0): _a(a){++N;}A(const A& aa): _a(aa._a){++N;}private:int _a;
};void f(A a)
{}int main(void)
{A a1;A a2 = 1;//隐式类型转换f(a1);cout << N << endl;return 0;
}

在这里插入图片描述
由于我们的N定义的是全局变量,这样我们可以在任意位置进行修改,如果我们进行恶意修改的话,我们的出来的数据就不是准确的了。

int main()
{A a1;A a2 = 1;f(a1);cout << cnt << endl;count++;   // 我可以修改它 return 0;
}

有没有办法可以把 N和类贴合起来呢?让这个N专门用来计算我 A 这个类的。
我们先试着把它定义成 —— 成员变量:

class A {
public:A(int a = 0): _a(a){++_N;}A(const A& aa): _a(aa._a){++_N;}private:int _a;int _N // 定义成成员变量
};

但是这样还是不行!这样的话每个对象里面都有一个 count, 我们是希望的是每个对象创建的时候去++的是同一个变量,而不是每个对象里面都有一个。
那该怎么办呢?

类里面可以定义静态成员,在成员变量前面加一个 static,就是静态成员。

我们接着往下看:

概念

声明为static的类成员称为类的静态成员。用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化

class A {
public:A(int a = 0): _a(a){++_N;}A(const A& aa): _a(aa._a){++_N;}
private:int _a;static int _N// 静态成员变量属于整个类,所有对象,生命周期在整个程序运行期间
};

特性

1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区

#include <iostream>
using namespace std;
class Test
{
private:static int _n;
};
int main()
{cout << sizeof(Test) << endl;return 0;
}

结果计算Test类的大小为1,因为静态成员_n是存储在静态区的,属于整个类,也属于类的所有对象。所以计算类的大小或是类对象的大小时,静态成员并不计入其总大小之和。

2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

class Test
{
private:static int _n;//声明
};
// 静态成员变量的定义初始化
int Test::_n = 0;

3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 - - 在下方详细讲解。

4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

class Test
{
public://没有this指针,只能访问静态成员static void Fun(){cout << _a << endl; //error不能访问非静态成员cout << _n << endl; }
private:int _a; //非静态成员static int _n; //静态成员
};

5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。- - - 生命周期是全局的,作用域受类域影响。

静态成员函数的访问

1.当静态成员变量为公有时,我们就可以在类外对它进行访问,有以下几种访问方式:

class A {
public:A(int a = 0): _a(a){++_N;}A(const A& aa): _a(aa._a){++_N;}private:int _a;public:static int _N;
};// 静态成员变量的定义初始化
int A::_N = 0;void f(A a)
{}int main(void)
{A a1;A a2 = 1;//隐式类型转换f(a1);/* 这里不是说是在 a1 里面找,这里只是帮助他突破类域罢了 */cout << a1._N << endl;cout << A::_N << endl; //2.通过类名突破类域进行访问return 0;
}

2.当静态成员变量为私有时:

我们可以提供一个公有的成员函数。我们写一个公有的 GetN成员函数,让它返回_N的值,这样我们就可以在类外调用该函数,就可以访问到它了。

还有没有更好的方式?让我不用对象就可以访问到它呢?

静态成员函数:

static int GetN() {return _N;
}
class A {
public:A(int a = 0): _a(a){++_N;}A(const A& aa): _a(aa._a){++_N;}// 没有this指针,只能访问静态成员static int GetN(){return _N;}
private:int _a;public:static int _N;
};// 静态成员变量的定义初始化
int A::_N = 0;void f(A a)
{}int main(void)
{A a1;A a2 = 1;//隐式类型转换f(a1);cout << a1._N << endl;//1.通过对象调用成员函数进行访问cout << A::GetN() << endl; //2.通过类名调用静态成员函数进行访问return 0;
}

三、友元

友元分为友元函数和友元类。友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

友元分为:友元函数友元类

友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部普通函数不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

我们在上一篇实现日期类的时候,对输入输出的运算符进行了重载: operator<<operator>>
我们知道,对流提取和流插入操作符是不能重载成类的成员函数的。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置:this指针默认是第一个参数,即左操作数,但是实际使用中cout需要是第一个形参对象才能正常使用。

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧ostream & operator<<(ostream& _cout){_cout << _year << "-" << _month << "-" << _day << endl;return _cout;}
private:int _year;int _month;int _day;
};

所以我们要将operator<<重载为全局函数,但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。(operator>>同理)

所以,我们若是想让<<和>>也自动识别我们的日期类,就需要我们自己写出对应的运算符重载函数。

class Date
{//友元函数friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

注意: 其中cout是ostream类的一个全局对象,cin是istream类的一个全局变量,<<和>>运算符的重载函数具有返回值是为了实现连续的输入和输出操作。

友元函数说明:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中非公有成员。

class A
{// 声明B类是A类的友元类,所以B类中的所有成员函数都可以是A类的友元函数friend class B;
public:A(int n = 0):_n(n){}
private:int _n;
};
class B
{
public:void Test(A& a){// B类可以直接访问A类中的私有成员变量cout << a._n << endl;}
};

友元类说明:

  • 友元关系是单向的,不具有交换性。
    例如上述代码中,B是A的友元,所以在B类中可以直接访问A类的私有成员变量,但是在A类中不能访问B类中的私有成员变量。
  • 友元关系不能传递
    如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  • 友元关系不能继承,在继承位置再给大家详细介绍。

四、内部类

概念: 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
注意:

  1. 内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。
  2. 外部类对内部类没有任何优越的访问权限
  3. 内部类天生就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
// 相当于两个独立的类
// B类的访问受A的类域和访问限定符的限制
class A
{
private:int _a;static int k;public: // B天生就是A的友元class B{int _b;void foo(const A& a){cout << k << endl;//OKcout << a._a << endl;//OK}};
};int A::k = 1;int main()
{cout << sizeof(A) << endl;A aa;cout << sizeof(aa) << endl;A::B bb;return 0;
}

在这里插入图片描述

五、匿名对象

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;}
};
A F()
{//A ret(10);//return ret;return A(10);
}
int main()
{// 有名对象A aa0;A aa1(1);A aa2 = 2;//A aa3();// 匿名对象 --声明周期当前这一行A();A(3);//Solution so;//so.Sum_Solution(10);Solution().Sum_Solution(10);return 0;
}

六、拷贝对象时的一些编译器优化

请看以下代码:

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;
}A f3()
{/*A aa(10);return aa;*/return A(10);
}int main()
{// 优化场景1A aa1 = 1;  // A tmp(1) + A aa1(tmp) -> 优化 A aa1(1)//优化场景2f1(A(1));  // 构造 + 拷贝构造  -> 优化 构造f1(1);  // 构造 + 拷贝构造  -> 优化 构造//优化场景3f2();	  // 构造+拷贝构造A ret = f2(); // 构造+拷贝构造+拷贝构造 ->优化 构造+拷贝构造//优化场景4A ret = f3();  //  构造+拷贝构造+拷贝构造 -> 优化 -> 构造return 0;
}

优化场景1:

A aa1 = 1;  // A tmp(1) + A aa1(tmp) -> 优化 A aa1(1)
//构造 + 拷贝构造 ->优化 构造

优化场景2:

f1(A(1));  // 构造 + 拷贝构造  -> 优化 构造
f1(1);  // 构造 + 拷贝构造  -> 优化 构造

优化场景3:

f2();	  // 构造+拷贝构造
A ret = f2(); // 构造+拷贝构造+拷贝构造 ->优化 构造+拷贝构造

在这里插入图片描述

优化场景4:

A ret = f3();  //  构造+拷贝构造+拷贝构造 -> 优化 -> 构造

在这里插入图片描述

相关文章:

【C++初阶】四、类和对象(下)

文章目录一、再谈构造函数构造函数体赋值初始化列表explicit关键字二、Static成员引入- 计算类中创建了多少个类对象概念特性静态成员函数的访问三、友元友元函数友元类四、内部类五、匿名对象六、拷贝对象时的一些编译器优化一、再谈构造函数 构造函数体赋值 在创建对象时&a…...

IDEA maven没有Import Maven projects automatically解决办法

去年装了个 IDEA2022版本 配置maven时我才发现是个大坑 他没有import Maven projects automatically配置项 当时看到我人都麻了 然后项目呢 用了依赖 这东西还不会自动下依赖 整的我那是相当难受 还在最后还是找到了解决办法 我们在配置文件上点击右键 然后鼠标选择如下图选项…...

Java实习生------MySQL10道面试题打卡

今日语录&#xff1a;“没有执行力&#xff0c;就没有竞争力 ”&#x1f339; 参考资料&#xff1a;图解MySQL、MySQL面试题 1、事务有哪些特性&#xff1f; 原子性&#xff1a; 一个事务中的所有操作&#xff0c;要么全部完成&#xff0c;要么全部不完成&#xff0c;不会出现…...

帆软报表设计器 数据集之数据库查询

当点击数据库查询时,调用TableDataTreePane的 public void actionPerformed(ActionEvent var1) {TableDataTreePane.this.dgEdit(this.getTableDataInstance().creatTableDataPane(), TableDataTreePane.this.createDsName(this.getNamePrefix()), false);} 然后调用TableDat…...

CSDN 第三十七期竞赛题解

很少有时间来玩玩题目&#xff0c;上一次因为环境极为嘈杂的原因在时间上没有进入前十&#xff0c;挺遗憾的。 在 CSDN 参加的第一次没出锅的比赛。 大概只有最后一题值得好好讲讲。 T1&#xff1a;幼稚班作业 幼稚园终于又有新的作业了。 老师安排同学用发给同学的4根木棒拼接…...

Vue实战【常用的Vue小魔法】

目录&#x1f31f;前言&#x1f31f;能让你首次加载更快的路由懒加载&#xff0c;怎么能忘&#xff1f;&#x1f31f;你是否还记得有一个叫Object.freeze的方法&#xff1f;&#x1f31f;异步组件那么强&#xff0c;你是不是没用过&#xff1f;&#x1f31f;你是不是还在comput…...

用C跑爬虫

爬虫自指定的URL地址开始下载网络资源&#xff0c;直到该地址和所有子地址的指定资源都下载完毕为止。 下面开始逐步分析爬虫的实现。 待下载集合与已下载集合 为了保存需要下载的URL&#xff0c;同时防止重复下载&#xff0c;我们需要分别用了两个集合来存放将要下载的URL和…...

【C语言】你真的了解结构体吗

引言✨我们知道C语言中存在着整形(int、short...)&#xff0c;字符型(char)&#xff0c;浮点型(float、double)等等内置类型&#xff0c;但是有时候&#xff0c;这些内置类型并不能解决我们的需求&#xff0c;因为我们无法用这些单一的内置类型来描述一些复杂的对象&#xff0c…...

血氧仪是如何得出血氧饱和度值的?

目录 一、血氧饱和度概念 二、血氧饱和度监测意义 三、血氧饱和度的监测方式 四、容积脉搏波计算血氧饱和度原理 五、容积脉搏波波形的测量电路方案 1&#xff09;光源和光电探测器的集成测量模块&#xff1a;SFH7050—反射式 2&#xff09;模拟前端 六、市面上血氧仪类型…...

Java全栈知识(3)接口和抽象类

1、抽象类 抽象类就是由abstract修饰的类,其中没有只声明没有实现的方法就是抽象方法&#xff0c;抽象类中可以有0个或者多个抽象方法。 1.1、抽象类的语法 抽象类不能被final修饰 因为抽象类是一种类似于工程中未完成的中间件。需要有子类进行继承完善其功能&#xff0c;所…...

JavaScript == === Object.is()

文章目录JavaScript & & Object.is() 相等运算符 全等运算符Object.is() 值比较JavaScript & & Object.is() 相等运算符 相等运算符&#xff0c;会先进行类型转换&#xff0c;将2个操作数转为相同的类型&#xff0c;再比较2个值。 console.log("10&…...

GPT4论文翻译 by GPT4 and Human

GPT-4技术报告解读 文章目录GPT-4技术报告解读前言&#xff1a;摘要1 引言2 技术报告的范围和局限性3 可预测的扩展性3.1 损失预测3.2 人类评估能力的扩展4 能力评估4.1 视觉输入 !!!5 限制6 风险与缓解&#xff1a;7 结论前言&#xff1a; 这篇报告内容太多了&#xff01;&am…...

inode和软硬链接

文章目录&#xff1a;一、理解文件系统1.1 什么是inode1.2 磁盘了解1.2.1磁盘的硬件结构1.2.2 磁盘的分区1.2.3 EXT2文件系统二、软硬链接2.1 软链接2.2 硬链接一、理解文件系统 1.1 什么是inode inodes 是文件系统中存储文件元数据的数据结构。每个文件或目录都有一个唯一的 …...

简单分析Linux内核基础篇——initcall

写过Linux驱动的人都知道module_init宏&#xff0c;因为它声明了一个驱动的入口函数。 除了module_init宏&#xff0c;你会发现在Linux内核中有许多的驱动并没有使用module_init宏来声明入口函数&#xff0c;而是看到了许多诸如以下的声明&#xff1a; static int __init qco…...

硬件速攻-AT24CXX存储器

AT24C02是什么&#xff1f; AT24CXX是存储芯片&#xff0c;驱动方式为IIC协议 实物图&#xff1f; 引脚介绍&#xff1f; A0 地址设置角 可连接高电平或低电平 A1 地址设置角 可连接高电平或低电平 A2 地址设置角 可连接高电平或低电平 1010是设备前四位固定地址 &#xf…...

C# tuple元组详解

概念 本质就是个数据结构&#xff0c;它是将多个数据元素分组成一个轻型数据结构。 如何声明元组变量&#xff08;针对.net framework 4.7 和 .net core 2.0) 不带字段名称元组 ## t1就是个变量 它的类型是元组类型 ## 左侧括号定义的是参数列表 等于号右侧就是个t1赋值 #…...

1、Linux初级——linux命令

下载镜像&#xff1a;http://cn.ubuntu.com/dowload 一、基本命令 1、alias&#xff08;给命令取别名&#xff09; 例如&#xff1a;alias clls -la&#xff08;只是临时的&#xff09; 2、配置文件$ vim ~/.bashrc $ vim ~/.bashrc // 使用vim打开配置文件 (1)在配置文件…...

ChatGPT助力校招----面试问题分享(四)

1 ChatGPT每日一题&#xff1a;电阻如何选型 问题&#xff1a;电阻如何选型 ChatGPT&#xff1a;电阻的选型通常需要考虑以下几个方面&#xff1a; 额定功率&#xff1a;电阻的额定功率是指电阻能够承受的最大功率。在选型时&#xff0c;需要根据电路中所需要的功率确定所选…...

【设计模式】创建型设计模式

文章目录1. 基础①如何学习设计模式② 类模型③ 类关系2. 设计原则3. 模板方法① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码4. 观察者模式① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码5. 策略模式① 定义②背景③ 要点④ 本质⑤ 结构图⑥ 样例代码1. 基础 ①如何学习…...

Linux 信号(signal):信号的理解

目录一、理解信号1.信号是什么2.信号的种类二、简单理解信号的生命周期一、理解信号 1.信号是什么 Linux中的信号其实和日常生活中的信号还是挺像的&#xff0c;LInux中的信号是一种事件通知机制&#xff0c;通知进程发生了某个事件。进程接收到信号后&#xff0c;就会中断当前…...

Vulnhub项目:Web Machine(N7)

靶机地址&#xff1a;Web Machine(N7)渗透过程&#xff1a;kali ip&#xff1a;192.168.56.104&#xff0c;靶机ip&#xff0c;使用arp-scan进行查看靶机地址&#xff1a;192.168.56.128收集靶机开放端口&#xff1a;nmap -sS -sV -T5 -A 192.168.56.128开放了80端口&#xff0…...

Qt基础之三十三:海量网络数据实时显示

开发中我们可能会遇到接收的网络数据来不及显示的问题。最基础的做法是限制UI中加载的数据行数,这样一来可以防止内存一直涨,二来数据刷新非常快,加载再多也来不及看。此时UI能看到数据当前处理到什么阶段就行,实时性更加重要,要做数据分析的话还得查看日志文件。 这里给出…...

linux console快捷键

Ctrl C&#xff1a;终止当前正在运行的程序。Ctrl D&#xff1a;关闭当前终端会话。Ctrl Z&#xff1a;将当前程序放入后台运行。Ctrl L&#xff1a;清除当前屏幕并重新显示命令提示符。Ctrl R&#xff1a;在历史命令中进行逆向搜索。Ctrl A&#xff1a;将光标移动到行首…...

弗洛伊德龟兔赛跑算法(弗洛伊德判圈算法)

弗洛伊德( 罗伯特・弗洛伊德)判圈算法(Floyd Cycle Detection Algorithm)&#xff0c;又称龟兔赛跑算法(Tortoise and Hare Algorithm)&#xff0c;是一个可以在有限状态机、迭代函数或者链表上判断是否存在环&#xff0c;以及判断环的起点与长度的算法。昨晚刷到一个视频&…...

nodejs篇 express(1)

文章目录前言express介绍安装RESTful接口规范express的简单使用一个最简单的服务器&#xff0c;仅仅只需要几行代码便可以实现。restful规范的五种接口类型请求信息req的获取响应信息res的设置中间件的使用自定义中间件解决跨域nodejs相关其它内容前言 express作为nodejs必学的…...

Java实习生------Redis常见面试题汇总(AOF持久化、RDB快照、分布式锁、缓存一致性)⭐⭐⭐

“年轻人&#xff0c;就要勇敢追梦”&#x1f339; 参考资料&#xff1a;图解redis 目录 谈谈你对AOF持久化的理解&#xff1f; redis的三种写回策略是什么&#xff1f; 谈谈你对AOF重写机制的理解&#xff1f;AOF重写机制的具体过程&#xff1f; 谈谈你对RDB快照的理解&a…...

seata服务搭建

它支持两种存储模式&#xff0c;一个是文件&#xff0c;一个是数据库&#xff0c;下面我们分别介绍一下这两种配置nacos存储配置&#xff0c;注意如果registry.conf中注册和配置使用的是file&#xff0c;就会去读取file.config的配置&#xff0c;如果是nacos则通过nacos动态读取…...

Kafka和RabbitMQ有哪些区别,各自适合什么场景?

目录标题1. 消息的顺序2. 消息的匹配3. 消息的超时4. 消息的保持5. 消息的错误处理6. 消息的吞吐量总结1. 消息的顺序 有这样一个需求&#xff1a;当订单状态变化的时候&#xff0c;把订单状态变化的消息发送给所有关心订单变化的系统。 订单会有创建成功、待付款、已支付、已…...

用Pytorch构建一个喵咪识别模型

本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 目录 一、前言 二、问题阐述及理论流程 2.1问题阐述 2.2猫咪图片识别原理 三、用PyTorch 实现 3.1PyTorch介绍 3.2PyTorch 构建模型的五要素 3.3PyTorch 实现的步骤 3.3.…...

QT搭建MQTT开发环境

QT搭建MQTT开发环境 第一步、明确安装的QT版本 注意&#xff1a; 从QT5.15.0版本开始&#xff0c;官方不再提供离线版安装包&#xff0c;除非你充钱买商业版。 而在这里我使用的QT版本为5.15.2&#xff0c;在线安装了好久才弄好&#xff0c;还是建议使用离线安装的版本 在这里…...