【C++】深入理解类和对象(3)

news2024/9/20 14:49:04

励志冰檗:形容在清苦的生活环境中激励自己的意志。💓💓💓 

目录

  ✨说在前面

🍋知识点一:再探构造函数

🍋知识点二:类型转换

🍋知识点三:static成员

🍋知识点四:友元

🍋知识点五:内部类

🍋知识点六:匿名对象

🍋知识点七:对象拷贝时编译器的优化

 • ✨SumUp结语


  ✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,前面几篇文章中我带大家学习了C++中的第一大难关——类和对象,今天我们来给大家收个尾,将类和对象结束。如果大家没有掌握好前面两篇文章,可以再回去看看,复习一下,再进入今天的内容。

今天我们将要学习C++中类和对象的最后一块部分。如果大家准备好了,那就接着往下看吧~

  👇👇👇
💘💘💘知识连线时刻(直接点击即可)

【C++】深入理解类和对象(1)

【C++】深入理解类和对象(2)

  🎉🎉🎉复习回顾🎉🎉🎉

        

 博主主页传送门:愿天垂怜的博客

​​

🍋知识点一:再探构造函数

🔥之前我们实现实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是以逗号分割的数据成员列表,每一个“成员变量”后面跟一个放在括号中的初始值或表达式。

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

🔥引用成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会报错。

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

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

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

#include <iostream>
using namespace std;

class Date
{
public:
	//初始化列表
	Date(int& rx, int year, int month, int day)
		//成员变量定义
		:_year(year)
		, _month(month)
		, _day(day)
		, _n(1)
		, _ref(rx)

	{
		//error
		//_n = 1;
	};

	void Print() const
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	//声明
	int _year;
	int _month;
	int _day;

	//const常量成员只能在初始化列表中初始化
	const int _n;

	//引用成员只能在初始化列表中初始化
	int& _ref;
};

int main()
{
	int x = 0;
	//对象定义
	Date d1(x, 2024, 7, 16); 

	//const变量只能在定义的时候初始化一次
	//const int x = 1;
	//x = 1;

	return 0;
}

我们来分析一下上面的代码:

在日期类Date中,我们可以注意到构造函数的写法,冒号后面是初始化列表成员变量,小括号里面是函数体,可以两种方式混用来实现构造函数。

但是对于const修饰的常量成员和引用成员是不可以用函数体内赋值这种方式来初始化的,只能在初始化列表中进行初始化。

#include <iostream>
using namespace std;

class Time
{
public:
	Time(int hour = 0)
		:_hour(hour)
	{
		cout << "Time()" << endl;
	}
private:
	int _hour;
};


class Date
{
public:
	//初始化列表
	Date(int& rx, int year, int month, int day)
		//成员变量定义
		:_year(year)
		, _month(month)
		, _day(day)
		, _n(1)
		, _ref(rx)

		//如果没有合适的默认构造函数
		, _t(1)

		, _ptr((int*)malloc(12))

	{
		if (_ptr == nullptr)
		{
			perror("malloc operation failed");
			return;
		}
		else
		{
			memset(_ptr, 0, 12);
		}
	};

	void Print() const
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	//C++11,声明,缺省值->初始化列表用的
	int _year = 1;
	int _month = 1;
	int _day = 1;

	//const常量成员只能在初始化列表中初始化
	const int _n;

	//引用成员只能在初始化列表中初始化
	int& _ref;

	//会调用Time _t的默认构造函数
    Time _t = 1;

    int* _ptr = (int*)malloc(12);
};

int main()
{
	int x = 0;
	//对象定义
	Date d1(x, 2024, 7, 16); 

	//const变量只能在定义的时候初始化一次
	//const int x = 1;
	//x = 1;

	return 0;
}

我们再来看上面的代码,这个代码在第一个代码的基础上增加了时间类Time。如果我们将Time类型的变量_t作为Date的成员,那么如果在初始化列表中没有初始化_t,那么会调用_t的默认构造函数进行初始化,如果没有合适的默认构造那么程序就不能执行。

需要注意的是,像_ptr这样动态申请的变量,如果只在初始化列表中进行初始化,那么没办法验证_ptr为NULL的情况,所以需要再函数体内再进行一次判断,需要两种方法混用。

同时,我们要理解每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。也就是说,如果我们将_day(day)去掉,也就是没有初始化_day,那么_day也会走初始化列表,_day是定义了的。

总结强调:

每个构造函数都有初始化列表,每个成员都要走初始化列表。对于没有在初始化列表的成员如果有缺省值就使用缺省值,如果没有缺省值且是内置类型则不确定(看编译器,大概率是随机值),如果是自定义类型则调用它的默认构造函数,如果没有合适的默认构造函数则报错。

引用变量、const变量、没有默认构造的自定义三类变量必须在初始化列表初始化。

我们再看下面这一道题目:

#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();
}

上面程序的运行结果是什么()

A.输出1 1        B.输出2 2        C.编译报错        D.输出 1 随机值        E.输出1 2        F,输出2 1 

答案是D.

那为什么是输出1 随机值呢?首先,A.aa(1)实例化调用构造函数,由于成员变量定义初始化的顺序和声明顺序一致,所以先初始化_a2,而此时_a1还没有定义,将_a2初始化为_a1为随机值。

然后,再定义_a1为a,而a为1,所以输出为1 随机值。

​​

🍋知识点二:类型转换

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

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

类型转换示例:

#include <iostream>
using namespace std;

class A
{
public:
	//explicit A(int a = 0) 不支持隐式类型转换
	 A(int a = 0)
	{
		_a1 = a;
	}

	A(const A& aa)
	{
		_a1 = aa._a1;
	}

	A(int a1, int a2)
		 :_a1(a1)
		, _a2(a2)
		{}

	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a1;
	int _a2;
};

class Stack
{
public:
	void Push(const A& aa)
	{
		//...
	}
private:
	A _arr[10];
	int _top;
};

int main()
{
	A aa1(1);
	aa1.Print();

	//隐式类型转换
	//2构造一个A的临时对象,在用这个临时对象拷贝构造aa2
	//编译器遇到连续构造+拷贝构造->优化为直接构造
	A aa2 = 2;
	aa2.Print();

	A& raa1 = aa2;
	const A& raa2 = 2;

	//类型转换的意义
	Stack st;
	A aa3(3);
	st.Push(aa3);

	st.Push(3);

	//C++11多参数情况
	A aa5 = { 1, 1 };
	const A& raa6 = { 2,2 };
	st.Push(aa5);
	st.Push({ 2,2 });

	return 0;
}

上面的代码中,我们先从main函数开始看。A aa1(1)实例化了一个类类型对象,并对其中第一个成员变量_a1进行了初始化,而_a2为随机值。而接下来,我们看到A aa2 = 2这样的写法,这是一个类型转换,将2这样的整型转换为类类型,属于隐式类型转换,需要创建临时变量,所以会先将2构造一个A的临时对象,在用这个临时对象调用拷贝构造函数拷贝到aa2中,实现类型转换,其效果就是将_a1初始化为2,而_a2为随机值。C++11后,对于多参数的情况也可以进行类型转换。

 ​​

🍋知识点三:static成员

🔥用static修饰的成员变量,称之为静态成员变量,静态变量一定要在类外面进行初始化。

🔥静态成员变量为当前类的所有对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。

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

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

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

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

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

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

示例:static变量的使用

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		++_scount;
	}
	A(const A& t)
	{
		++_scount;
	}	

	~A()
	{
		 --_scount;
	}
	//静态成员函数
	static int GetACount()
	{
		//++_a;
		//没有this指针,不能访问非静态成员变量	this->_a
		return _scount;
	}
//private:
	//类里面声明
	static int _scount;
	int _a;
};

//类外面初始化
int A::_scount = 0;

int main()
{
	//大小为1,不包含静态变量,它存在静态区
	cout << sizeof(A) << endl;

	//公有情况下,可以用A::_scount或a1_.scount
	cout << A::_scount << endl;

	//否则用静态成员函数获取
	cout << A::GetACount() << endl;
	A a1, a2;
	{
		A a3(a1);
		cout << A::GetACount() << endl;
	}
	cout << A::GetACount() << endl;
	cout << a1.GetACount() << endl;

	return 0;
}

我们看到上面的代码,在类A中定义了成员变量_a和_scount,其中_scount是静态变量,是生命周期是全局的,需要在类外部定义和初始化,我们看到main函数中计算A的大小也没有包括静态变量。在公有的情况下,我们可以用A::_scount或者对象._scount来访问静态成员变量。在私有的情况下,我们通常在类中使用静态成员函数获取静态变量,如上面的GetACount()。

我们来做一道看似简单,但并没有那么简单的题目:

题目链接:求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)

题目描述:

题目分析:
思路:这道题限制了我们不能使用循环、不能使用递归、不能使用条件判断也不能使用等差数列求和公式,那我们就可以考虑用一个类,这个类中声明静态变量_count和_sum且在类外定义初始化为0,且将构造函数每执行一次就++_count。由于_count是静态变量,每次的值并不会改变,那么每次++_count的同时_sum+=_count,就可以将_conut每次的值加到_sum中。那么现在的问题就是,如何让它构造n次?

其实很简单,我们只要定义一个边长数组arr[n],里边有n个元素,就会调用n次构造函数,_count就会++n次,就达到了我们的目的。

代码如下:

class Sum
{
public:
    Sum()
    {
        _count++;
        _sum += _count;
    }
    static int GetSum()
    {
        return _sum;
    }
private:
    static int _count;
    static int _sum;    
};

int Sum::_count = 0;
int Sum::_sum = 0;

class Solution {
public:
    int Sum_Solution(int n) {
        Sum arr[n];

        return Sum::GetSum();
    }
};

我们再来看这样一道题:

设已经有A,B,C,D 4个类的定义,程序中A,B,C,D构造函数调用顺序为?()

设已经有A,B,C,D 4个类的定义,程序中A,B,C,D析构函数调用顺序为?()

A:D B A C        B:B A D C        C:C D B A        D:A B D C        E:C A B D        F:C D A B

#include <iostream>
using namespace std;

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

	return 0;
}

答案:E B

由于全局变量在main函数之前就创建,所以c肯定是要最先创建的;其次,局部对象按照出现的顺序进行构造,无论是否为static,所以构造的顺序是C A B D。

对于析构函数,并不是单纯的将构造的顺序反过来,同时要考虑static变量生命周期发生改变,在局部变量之后进行析构,所以析构的顺序是D B A C。

 ​​

🍋知识点四:友元

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

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

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

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

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

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

🔥友元类关系不能传递,如果A是B的友元,B是C的友元,B是C的友元,但是A不是C的友元。(我附庸的附庸不是我的附庸)。

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

示例1:一个函数可以是多个类的友元函数

#include <iostream>
using namespace std;

//前置声明,否则A的友元函数声明编译器不认识B
class B;

class A
{
	//友元声明
	friend void function(const A& aa, const B& bb);
	//类型变量向上找,找不到B
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
	//友元声明
	friend void function(const A& aa, const B& bb);
private:
	int _b1 = 3;
	int _b2 = 4;
};

void function(const A& aa, const B& bb)
{
	cout << aa._a1 << endl;
	cout << bb._b1 << endl;
}

int main()
{
	A aa;
	B bb;
	function(aa, bb);

	return 0;
}

示例2:友元类

#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.Func2(aa);

	return 0;
}

​​

🍋知识点五:内部类

🔥如果一个类定义在另一个的类内部,这个内部类就叫做内部类。内部类是一个独立的类,跟定义在全局相比,它只是受外部类类域限制和访问限定符的限制,所以外部类定义的对象中不包含内部类。

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

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

示例:内部类的使用

#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;//OK
			cout << a._h << endl;//OK
		}
	private:
		int _b = 1;
	};
};

int A::_k = 1;

int main()
{
	cout << sizeof(A) << endl;
	A::B b;
	A aa;
	b.foo(aa);

	return 0;
}

所以我们再回过头去看static成员时的那道题,也可以直接将Sum作为Solution的友元这样写:

class Solution {
private:
    static int _count;
    static int _sum;
    class Sum
    {
    public:
        Sum()
        {
            _count++;
            _sum += _count;
        }
        static int GetSum()
        {
            return _sum;
        } 
    };
public:
    int Sum_Solution(int n) {
        Sum arr[n];

        return Sum::GetSum();
    }
};

int Solution::_count = 0;
int Solution::_sum = 0;

​​

🍋知识点六:匿名对象

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

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

 示例:匿名对象的使用

#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(1);

	//有名对象调用
	Solution st;
	int ret1 = st.Sum_Solution(10);
	cout << ret1 << endl;
	
	//匿名对象在这样场景下就很好用
	int ret2 = Solution().Sum_Solution(10);
	cout << ret2 << endl;

	return 0;
}

这里再给大家补充一个知识点,我们在C语言中学习过qsort,忘了的可以看这一篇博客:C语言-深入理解指针(4)

#include <iostream>
using namespace std;

int int_compare(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}

int main()
{
	int arr[] = { 32,70,12,45,26,80,53,33 };
	qsort(arr, 8, sizeof(int), int_compare);
	for (int i = 0; i < 8; i++)
	{
		cout << arr[i] << " ";
	}

	return 0;
}

在C++中,我们不再频繁使用qsort,而是利用sort替代,但是需要包含头文件algorithm:

#include <iostream>
using namespace std;
#include <algorithm>

int main()
{
	int arr[] = { 32,70,12,45,26,80,53,33 };
	sort(arr, arr + 8);
	for (int i = 0; i < 8; i++)
	{
		cout << arr[i] << " ";
	}

	return 0;
}

注意,qsort和sort默认都是升序排序,如果需要降序需要进行相应的操作。如将qort中的比较函数改为判断大于而不是小于。 

 ​​

🍋知识点七:对象拷贝时编译器的优化

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

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

大家先看下面的类A:

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

	void Print()
	{
		cout << "A::Print()" << endl;
	}
private:
	int _a1 = 1;
};

优化1:隐式类型转换

int main()
{
	//构造+拷贝构造->优化为直接构造
	A aa1 = 1;
	//若const引用,直接构造临时对象,然后引用该临时对象
	const A& aa2 = 1;

	return 0;
}

这个咱们在第二点就讲过,构造+拷贝构造会被优化为直接构造。所以,像第二句代码,1就会直接构造临时对象,然后被aa2引用。 

优化2:匿名对象传参

void f1(A aa)
{
	//...
}

int main()
{
	f1(A(1));//构造+拷贝构造

	return 0;
}

A(1)实例化匿名对象,调用构造函数,进而传参连续调用了构造和拷贝构造,也会被优化成直接构造 。

优化3:隐式类型转换+传参

void f1(A aa)
{
	//...
}

int main()
{
	f1(1);//构造+拷贝构造

	return 0;
}

同样道理,1需要先构造临时对象,临时对象拷贝构造传参, 连续调用构造和拷贝构造,被优化成直接构造。

优化4:VS2022“激进”优化

A f2()
{
	A aa(1);
	return aa;
}

int main()
{
	f2().Print();
	cout << endl;

	return 0;
}

根据我们学习的逻辑,f2返回的时候会调用拷贝构造函数创建临时变量,运行结果如下:


 

其中,第一个析构析构的是aa,第二个析构析构的是临时变量。而在VS2022上,它并不会生成aa,而是直接生成临时对象:

 

那我们假设在类中增加重载函数前置++,编译器还敢这么激进地优化吗?

//前置++	
A& operator++()
{
	++_a1;
	return *this;
}

A f2()
{
	A aa(1);
	++aa;
	return aa;
}

int main()
{
	f2().Print();
	cout << endl;

	return 0;
}

我们来看结果:

 

我们发现,及时对其进行前置++操作,也不会构造aa,一切都是在操作中间变量。 

   

 • ✨SumUp结语

到这里本篇文章的内容就结束了,本节是类和对象的最后一节,内容已经结束了。恭喜大家熬过了C++的第一大难关,下一篇文章开始不会有太大难度的上升。希望大家能够认真学习,打好基础,迎接接下来的挑战,希望大家继续捧场~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spl注入实战thinkphp

目录 一、环境的部署 二、本地创建数据库 三、填写数据库连接文件 四、编写控制器 五、访问分析 debug报错会显示物理路径 原因是config.php文件相关配置 六、注入分析 七、进入断点调试 八、通过mysql执行语句查看结果 九、总结&#xff1a; 一、环境的部署 二、本地…

【51单片机仿真】基于51单片机设计的智能六位密码锁(匿*输入/密码修改/警示/保存/恢复/初始密码)源码仿真设计文档演示视频——文末资料下载

基于51单片机设计的智能六位密码锁 演示视频 基于51单片机设计的智能六位密码锁 功能简介 - 能够从键盘中输入密码&#xff0c;并相应地在显示器上显示"*" - 能够判断密码是否正确&#xff0c;正确则开锁&#xff0c;错误则输出相应信息 - 能够实现密码的修改 -…

日志审计系统

1.1日志审计基础性知识 什么是日志&#xff1f; 传统的日志概念 信息系统中所有系统和应用必须包含的描述其自身运行和操作的特定数据记录。 广义的日志概念 针对特定记录目的&#xff0c;通过各种探测手段采集的信息数据&#xff0c;包括运行状态、所有事件及操作&#x…

从零开始实现循环神经网络

本节我们通过使用MXnet&#xff0c;来从零开始的实现一个含有隐藏状态的循环神经网络。 前序工作 数据集预处理进行采样 实现循环神经网络 完成前序工作后&#xff0c;即可开始实现循环神经网络。本文首先构建一个具有隐状态的循环神经网络。其结构如图所示&#xff1a; 接…

力扣面试经典算法150题:最后一个单词的长度

最后一个单词的长度 今天的题目是力扣面试经典150题中的数组的简单题: 最后一个单词的长度 题目链接&#xff1a;https://leetcode.cn/problems/length-of-last-word/description/?envTypestudy-plan-v2&envIdtop-interview-150 题目描述 给定一个仅包含大小写字母和空…

Broken靶机

查看靶机的mac地址 使用kail进行扫描ip 探测靶机主机&#xff0c;端口&#xff0c;服务 nmap -sS -sS -A -p- 192.168.154.137 进行目录扫描 dirsearch -u http://192.168.154.137 拼接后没什么发现 访问靶机ip 访问readme.md 发现是十六进制的值 将内容写入到readme.md中 使…

坐牢第二十五天20240813(网络通信)

一、TCP机械臂测试 通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#x…

C语言问答进阶--5、基本表达式和基本语句

赋值表达式 表达式是什么&#xff1f;表达式是由运算符和操作数组成的式子。 如下的代码 #include "iostream.h" int main() { int a1,b2,sum; cout<<(sumab)<<endl; return 0; } 那么如下的呢&#xff1f; #include "iostream.h" int mai…

智能建筑系统,实现智慧城市的可持续发展

智能建筑系统是指通过现代技术和通信技术&#xff0c;对建筑系统进行全方位、智能化的管理和控制。该系统可以通过各种传感器、安全监控系统和计算机设备对工程建筑的内外环境进行认知和控制&#xff0c;进而监控和管理建筑工程设备和信息。 智能建筑系统可以调节室温、湿度等环…

基于Hadoop的汽车大数据分析系统设计与实现【爬虫、数据预处理、MapReduce、echarts、Flask】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍爬虫数据概览HIve表设计Cars Database Tables1. cars_data2. annual_sales_volume3. brand_sales_volume4. city_sales_volume5. sales_volume_by_year_and_brand6. sales_distribu…

Mysql的完整性约束

主键约束&#xff1a;一个表中只有一个主键&#xff0c;通过主键找到唯一的记录。主键不能为空不能重复。 CREATE TABLE s1&#xff08;id TINYINT PRIMARY KEY UNSIGNEDINT AUTO_INCREAMENT,name VARCHAR(20) NOT NULL UNIQUE ,age TINYINT DEFAULT 18&#xff09;;…

镜像仓库认证信息加密初始化脚本

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…

Python爬虫——爬取bilibili中的视频

爬取bilibili中的视频 本次爬取&#xff0c;还是运用的是requests方法 首先进入bilibili官网中&#xff0c;选取你想要爬取的视频&#xff0c;进入视频播放页面&#xff0c;按F12&#xff0c;将网络中的名称栏向上拉找到第一个并点击&#xff0c;可以在标头中&#xff0c;找到…

【研发日记】嵌入式处理器技能解锁(三)——TI C2000 DSP的C28x内核

文章目录 前言 背景介绍 C28x内核 浮点单元(FPU) 快速整数除法单元(FINTDIV) 三角数学单元(TMU) VCRC单元 CPU总线 指令流水线 总结 参考资料 前言 见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》 见《【研发日记】嵌入式处理器技能解…

Linux--应用层自定义协议与序列化(例子:网络计算器)

目录 0.上篇文章 1.应用层 再谈一谈协议 网络版计算器 序列化 和 反序列化 2.重新理解 read、 write、 recv、 send 和 tcp 为什么支持全双工 3.网络计算器&#xff08;代码实现) 3.1序列化&反序列化的接口 3.2 项目逻辑 3.3 代码 3.3.1辅助库 3.3.2 基于TCP的…

非线性RCD负载:电力系统的智能管理

随着科技的不断发展&#xff0c;电力系统的规模日益扩大&#xff0c;复杂性也越来越高。在这种背景下&#xff0c;非线性RCD负载&#xff08;Resistive-Capacitive-Inductive load&#xff09;的出现&#xff0c;对电力系统的智能管理提出了新的挑战。非线性RCD负载是指由电阻、…

【学习笔记】Day 10

一、进度概述 1、《地震勘探原理》第三章 二、详情 3.1 野外工作概述 主要介绍地上与海上两种情况下的测量方法&#xff0c;这里不做详解&#xff0c;需要就看书。 其中简况分为&#xff1a;试验工作&#xff0c;生产工作过程&#xff0c;干扰波调查&#xff0c;干扰…

thinkphp8反序列化分析

thinkphp8反序列化 前言 摆了一个暑假&#xff0c;正好看见周会有人分析了tp反序列化&#xff0c;想起这条链子的发现者就是我尊敬的nivia&#xff0c;这不得好好分析一下&#xff0c;而且师傅也是分析了这个&#xff0c;所以有了这个文章 链子一 __call触发 分析 相比于我…

SpringSecurity+前端项目+redis完成认证授权的代码

1. 前端准备工作--都在全局main.js页面中设置的 1.1. 创建Vue工程后&#xff0c;并导入element ui和axios&#xff0c;添加连接后端项目的路径&#xff0c;把axios挂载到Vue 1.2. 前置路由守卫&#xff08;所有路由跳转前核实一下身份&#xff09; //前置路由守卫--所有的路由…

C++密码管理器

先问一句 最近有几个关注我的原力等级为0或-1&#xff0c;文章全是转载&#xff0c;转载时间基本都在2021年&#xff0c;而且关注了很多人&#xff0c;这些是僵尸粉吗&#xff1f; 文末有投票&#xff0c;麻烦参与一下谢谢 实现功能列表 暂时还没做加密功能 打算用openssl/a…