详解C++类和对象(中(类的6个默认成员函数))

文章目录

  • 写在前面
  • 1. 类的6个默认成员函数
  • 2. 构造函数
    • 2.1 构造函数的引入
    • 2.1 构造函数的特性
  • 3. 析构函数
    • 3.1 析构函数的引入
    • 3.2 析构函数的特性
  • 4. 拷贝构造函数
    • 4.1 拷贝构造函数概念
    • 4.2 拷贝构造函数的特性
    • 4.3 拷贝构造函数典型调用场景
  • 5. 赋值运算符重载
    • 5.1 运算符重载
    • 5.2 赋值运算符重载
  • 6. const成员函数
  • 7. 取地址及const取地址操作符重载

写在前面

这篇文章详细介绍了类的 6 个默认成员函数,它们是构造函数、析构函数、拷贝构造函数、赋值运算符重载、取地址和 const 取地址操作符重载以及const 成员函数。这些成员函数在 C++ 中是默认生成的,默认成员函数在类的设计和实现中起着非常重要的作用,下面我们来一一介绍。

1. 类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,在 C++ 中,即使一个类中看起来什么都没有,编译器会自动生成以下6个默认成员函数
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数
在这里插入图片描述

2. 构造函数

2.1 构造函数的引入

例如有如下一个类:

#include <iostream>
using namespace std;

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 d1, d2;
	d1.Init(2024, 2, 5);
	d2.Init(2024, 2, 6);

	d1.Print();
	d2.Print();

	return 0;
}

对于上面的Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?

在C++中为了让对象在实例化的时候能够完成初始化,提供了构造函数。构造函数是一种特殊的成员函数,用于在创建对象时对其进行初始化。在 C++ 中,构造函数的名称与类名相同,不返回任何值,甚至没有 void 类型的返回值。构造函数的主要作用是初始化对象的数据成员,确保对象在创建时有 一个合适的初始值。创建类类型对象时由编译器自动调用,并且在对象整个生命周期内只调用一次

2.1 构造函数的特性

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
    在这里插入图片描述
  4. 构造函数可以重载。
    在这里插入图片描述
  5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦
    用户显式定义编译器将不再生成。
    在这里插入图片描述
  6. 关于编译器生成的默认成员函数,我们会有疑惑:不实现构造函数的情况下,编译器会
    生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默
    认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的
    默认构造函数并没有什么用??

    其实不然,这是因为C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员
    函数。
    在这里插入图片描述
    注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在
    类中声明时可以给默认值。

    在这里插入图片描述
  7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
    注意:无参构造函数全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数即不需要传参就可以调用的构造函数
    在这里插入图片描述
    在实际编程中,如果对象的初始化值不依赖于外部参数,并且没有特殊的初始化需求,编译器生成的默认构造函数就够用。如果对象的初始化值依赖于外部参数,推荐缺省的默认构造函数,因为全缺省的传不传参都可以调用。

3. 析构函数

3.1 析构函数的引入

例如有如下一个类:

#include <iostream>
using namespace std;

class Stack
{

public:
	void Init(int capacity = 4)
	{
		int* tmp = (int*)malloc(sizeof(int) * capacity);
		if (tmp == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_nums = tmp;
		_capacity = capacity;
		_top = 0;
	}

	void Destroy()
	{
		if (_nums)
		{
			free(_nums);
			_nums = nullptr;
			_capacity = _top = 0;
		}
	}
	void push(int x)
	{

		//检查扩容
		//...
		_nums[_top++] = x;
	}
private:
	int* _nums;
	int _top;
	int _capacity;

};
int main()
{
	Stack st;
	st.Init();
	st.push(1);
	st.push(1);
	st.push(1);

	st.Destroy();
	return 0;
}

对于上面的Stack类,可以通过Destroy公有方法清理对象中的资源(动态申请的空间),但如果每次使用完对象时都调用该方法来主动的释放资源,未免有点麻烦,那能否在对象销毁之前,就自动调用相关函数来清理对象中的资源呢?

在C++中,可以通过析构函数来实现在对象销毁之前自动清理对象中的资源。析构函数是特殊的成员函数,该函数与构造函数功能相反,完成的不是对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会编译器会自动调用析构函数,完成对象中资源的清理工作

3.2 析构函数的特性

  1. 析构函数名是在类名前加上字符 ~。

  2. 无参数无返回值类型。

  3. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
    在这里插入图片描述

  4. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。

  5. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器
    生成的默认析构函数,对自定类型成员调用它的析构函数。
    在这里插入图片描述

#include <iostream>
using namespace std;
class B
{
public:
	B(int b = 0)
	{
		_b = b;
		cout << "B(int b = 0)" << endl;
	}
	~B()
	{
		cout << "~B()" << endl;
	}
private:
	int _b;
};


class A
{
public:
	
private:
	int _a;
	B _bb;
};


int main()
{
	A a;
	return 0;
}

上面程序运行结束后输出:~B()。
而在main方法中根本没有直接创建B类的对象,为什么最后会调用B类的析构函数?
因为:main函数中创建了A类的对象a,而a中包含2个成员变量,其中_a是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_bb是B类对象,所以在a销毁时,要将其内部包含的B类的_bb对象销毁,所以要调用B类的析构函数。但是:main函数中不能直接调用B类的析构函数,实际要释放的是A类对象,所以编译器会调用A类的析构函
数,而A没有显式提供,则编译器会给A类生成一个默认的析构函数,目的是在其内部调用B类的析构函数,即当A对象销毁时,要保证其内部每个自定义对象都可以正确销毁,main函数中并没有直接调用B类析构函数,而是显式调用编译器为A类生成的默认析构函数。
注意:创建哪个类的对象则调用该类的构造函数,销毁那个类的对象则调用该类的析构函数。

  1. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
    在这里插入图片描述

4. 拷贝构造函数

4.1 拷贝构造函数概念

拷贝构造函数是C++中的一种特殊成员函数,它通常用于在对象创建时,使用一个现有对象的内容来初始化新对象,从而实现对象的拷贝。
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用
语法形式如下:

class Date
{
public:
	//默认构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数,使用同类类型的对象初始化
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 2, 6);
	Date d2(d1);//使用 d1 拷贝构造 d2
	return 0;
}

4.2 拷贝构造函数的特性

  1. 拷贝构造函数是构造函数的一个重载形式。
    在这里插入图片描述
    需要注意的是:显示的写了拷贝构造以后,编译器就不会生成拷贝构造函数了,同时默认构造函数,编译器不会生成了,因为拷贝构造函数也是构造函数。
    在这里插入图片描述

  2. 拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用
    在这里插入图片描述

  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
    字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
    在这里插入图片描述

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

#include <iostream>
using namespace std;

class Stack
{

public:
	//构造函数
	Stack(int capacity = 4)
	{
		int* tmp = (int*)malloc(sizeof(int) * capacity);
		if (tmp == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_nums = tmp;
		_capacity = capacity;
		_top = 0;
	}
	//析构函数
	~Stack()
	{
		cout << "~Stack()" << endl;
		if (_nums)
		{
			free(_nums);
			_nums = nullptr;
			_capacity = _top = 0;
		}
	}
	
private:
	int* _nums;
	int _top;
	int _capacity;
};
int main()
{
	Stack st1;
	Stack st2(st1);//st1拷贝构造st2
	return 0;
}

当我们运行上面的程序时,发现代码崩溃,下面我们来分析一下,为什么代码会崩溃呢?
在这里插入图片描述
因此我们得出结论:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
在这里插入图片描述

4.3 拷贝构造函数典型调用场景

现有如下一个Date类:

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year;
	int _month;
	int _day;
};
  1. 使用已存在对象创建新对象
int main()
{
	Date d1;
	Date d2(d1);//使用 d1 拷贝构造 d2
	Date d3 = d2;//使用 d2 拷贝构造 d3

	return 0;
}

运行结果如下:
在这里插入图片描述
2. 函数参数类型为类类型对象

void func(Date d)
{
	cout << "void func(Date d)" << endl;
}
int main()
{
	Date d1;
	func(d1);

	return 0;
}

运行结果如下:
在这里插入图片描述
3. 函数返回值类型为类类型对象
在这里插入图片描述
结论:为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

5. 赋值运算符重载

5.1 运算符重载

C++为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。有了运算符重载以后,可以根据需求使得自定义类型的对象也可以像内置类型一样使用操作符。
函数名字为:关键字operator后面接需要重载的运算符符号
函数原型:返回值类型 operator操作符(参数列表)
关于运算符重载,有一下几点需要注意:

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

举个例子:比如想比较两个日期是否相等。
之前我们想比较两个日期的大小需要写一个比较大小的函数,现在有了运算符重载,我们可以重载运算符 ’ ==’ 使得Date类的对象可以像自定义类型一样使用运算符’ ==’ 来判断两个日期是否相等。

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
//private:
	int _year;
	int _month;
	int _day;
};
//运算符 == 重载,重载成全局的
bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}
int main()
{
	Date d1(2024, 2, 6);
	Date d2(2024, 2, 7);

	cout << (d1 == d2) << endl;//这里d1 和 d2可以像内置类型一样使用操作符
 	return 0;
}

代码运行结果:
在这里插入图片描述
上面将运算符重载成全局的有个很大的问题(上面能运行是因为将成员变量的访问限定符改成了public),就是运算符重载成全局的就需要成员变量是公有的,那么问题来了,封装性如何保证?
这里其实可以用我们后面学习的友元来解决,或者干脆重载成成员函数
在这里插入图片描述
因此正确的写法为:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	// 运算符 == 重载,重载成成员函数
	// bool operator==(Date* this, const Date& d)
	// 这里需要注意的是,左操作数是this,指向调用函数的对象
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 2, 6);
	Date d2(2024, 2, 7);

	cout << (d1 == d2) << endl;//这里d1 和 d2可以像内置类型一样使用操作符
	//上面那样写是为了提高代码的可读性,我们也可以像下面这样显示的调用
	cout << (d1.operator==(d2)) << endl;//bool operator==(Date* this, const Date& d2)

 	return 0;
}

总结:运算符函数可以定义为类的成员函数或全局函数。如果运算符函数是类的成员函数,它将自动获得一个隐含的 this 指针,用于访问调用对象的成员;如果是全局函数,则需要在参数列表中显式地传递所有操作数。

5.2 赋值运算符重载

  1. 赋值运算符重载是指重载类中的赋值运算符(=),使得用户能够对自定义类型的对象进行赋值操作。通过赋值运算符重载,可以实现类对象之间的拷贝。
    语法格式为:
    参数类型:const T&,传递引用可以提高传参效率。
    返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值。
    检测是否自己给自己赋值
    返回*this :要复合连续赋值的含义。
//T是类型名
T& operator=(const T& 变量名) 
{
    // 执行赋值操作
    // 返回 *this
}
  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数。
    在这里插入图片描述
    正确做法如下:

在这里插入图片描述在这里插入图片描述
3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
在这里插入图片描述
既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。像前面我们介绍拷贝构造函数那里的Stack类一样,我们发现程序就会崩溃掉。
原因如下:
在这里插入图片描述
总结:如果类中未涉及到资源管理(动态申请空间),赋值运算符是否实现都可以;一旦涉及到资源管理赋值运算符则必须要实现。

6. const成员函数

使用const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。并且在函数声明和定义中都需要加上 const 关键字。
语法如下:

返回类型 函数名() const 
{
    // 函数体
}

在这里插入图片描述
经过上面的介绍,我们来思考如下几个问题:

  1. const对象可以调用非const成员函数吗?
  2. 非const对象可以调用const成员函数吗?
  3. const成员函数内可以调用其它的非const成员函数吗?
  4. 非const成员函数内可以调用其它的const成员函数吗?

在这里插入图片描述

7. 取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

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

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

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。

创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !!!
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣面试150 数字范围按位与 公共前缀 位运算

Problem: 201. 数字范围按位与 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考 复杂度 时间复杂度: O ( 1 ) O(1) O(1) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public int rangeBitwiseAnd(int left, int right){int shift 0;while…

五、机器学习模型及其实现1

1_机器学习 1&#xff09;基础要求&#xff1a;所有的数据全部变为了特征&#xff0c;而不是eeg信号了 python基础已经实现了特征提取、特征选择&#xff08;可选&#xff09;进行了数据预处理.预处理指对数据进行清洗、转换等处理&#xff0c;使数据更适合机器学习的工具。S…

图数据库 之 Neo4j - Browser 介绍(3)

Neo4j Browser 介绍 Neo4j Browser 中有 3 个模块&#xff0c;侧边栏&#xff0c;Cypher 编辑器与结果栏&#xff0c;在进入 Neo4j Browser 时结果栏会展示欢迎界面。 Cypher 编辑器 Cypher 是一种图形查询语言&#xff0c;用于查询和操作图形数据库。它是 Neo4j 图形数据库的…

极限的反问题【高数笔记】

1. 什么是极限反问题&#xff1f; 2. 极限反问题分为几类&#xff1f; 3. 每一类极限反问题的具体做法是什么&#xff1f; 4. 每一类极限反问题具体做法是否有前提条件&#xff1f; 5. 例题&#xff1f;

板块一 Servlet编程:第一节 HTTP协议理论与服务器请求响应原理 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程&#xff1a;第一节 HTTP协议理论与服务器请求响应原理 一、HTTP特点二、HTTP中的 URL三、两种 HTTP 请求方法&#xff1a;GET 和 POST四、请求响应的底层请求头在服务器中表现响应头在服务器中表现 在上一个板块中我们完成了所有IDEA的基础配置工作&#xf…

深度测评:ONLYOFFICE 桌面编辑器 v8.0新功能

目录 前言 一、PDF表单处理&#xff1a;提升办公效率 二、RTL&#xff08;从右到左&#xff09;支持&#xff1a;满足不同语言习惯 三、Moodle集成&#xff1a;教育行业的新助力 四、本地界面主题&#xff1a;个性化办公体验 五、性能优化与稳定性提升 六、性能与稳定性…

C++泛编程(3)

类模板基础 1.类模板的基本概念2.类模板的分文件编写3.类模板的嵌套 在往节内容中&#xff0c;我们详细介绍了函数模板&#xff0c;这节开始我们就来聊一聊类模板。C中&#xff0c;类的细节远比函数多&#xff0c;所以这个专题也会更复杂。 1.类模板的基本概念 和函数模板一样…

Javascript入门学(基础)

软件篇 JS基础语法第一天 1.javascript介绍 1.1 js是什么 是什么 是一种运行在客户端&#xff08;浏览器&#xff09;的编程语言&#xff0c;实现人机交互效果&#xff0c;而html和css是标记性语言&#xff0c;并非编程语言有什么用 js的组成 htmlcssjs实现按钮点击功能 …

为什么程序员都不喜欢关电脑?

​​​​​​​我们百战卓越班的监管老师总是和我抱怨&#xff1a;这些学生们上完晚自习以后总是不记得关电脑&#xff0c;或者有的直接显示器都不管&#xff0c;直接把作业一交&#xff0c;拿上手机就走人了&#xff0c;这都是什么不好的习惯&#xff1f;难道他们都不喜欢关电…

树莓派智能自行车灯:亲,小心后方大卡车~

Raspberry Pi 计算模块 4 成本低、功耗低、结构紧凑、性能卓越&#xff0c;是 Velo AI 首次推出的道路安全产品的核心&#xff0c;该产品可提醒骑车人注意身后的车辆移动。 位于匹兹堡的 Velo AI 公司由机器人专家 Clarke Haynes 和人工智能专家 Micol Marchetti-Bowick 共同创…

政安晨:示例演绎TensorFlow的官方指南(一){基础知识}

为什么要示例演绎&#xff1f; 既然有了官方指南&#xff0c;咱们在官方指南上看看就可以了&#xff0c;为什么还要写示例演绎的文章呢&#xff1f; 其实对于初步了解TensorFlow的小伙伴们而言&#xff0c;示例演绎才是最重要的。 官方文档已经假定了您已经具备了相当合适的…

在容器中使用buildah构建镜像

简介 buildah是一个构建OCI标准镜像的工具&#xff0c;可以用来替代docker build 在常见的linux发行版中可直接通过包管理工具安装使用 # centos yum install buildah# ubuntu/debian apt install buildah# alpine apk add buildah其他发行版安装方法详见 github&#xff0c…

jsp教务管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 教务管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

【C生万物】C语言分支和循环语句

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

C++重新入门-C++变量作用域

目录 1.C变量定义 2.C作用域 3.局部变量 4.全局变量 5.块作用域变量 6.初始化局部变量和全局变量 1.C变量定义 一般来说有三个地方可以定义变量&#xff1a; 在函数或一个代码块内部声明的变量&#xff0c;称为局部变量。 在函数参数的定义中声明的变量&#xff0c;称为…

逆向工程:揭开科技神秘面纱的艺术

在当今这个科技飞速发展的时代&#xff0c;我们每天都在与各种电子产品、软件应用打交道。然而&#xff0c;你是否想过&#xff0c;这些看似复杂的高科技产品是如何被创造出来的&#xff1f;今天&#xff0c;我们就来探讨一下逆向工程这一神秘而又令人着迷的领域。 一、什么是…

WireShark使用教程(TCP/IP 部分情况居然变成三次挥手了???)

WireShark自学 WrieShark介绍WrieShark的应用常见协议包的抓取 WrieShark常用手段混杂模式 和 普通模式混杂模式打开方式普通模式 过滤器过滤器类型捕获过滤器显示过滤器语法捕获到的数据的列的含义常见的 Protocols - Values 键盘快捷键常用的过滤命令常用协议分析ARP 协议分析…

阿里云游戏服务器租用价格表,2024最新报价

阿里云游戏服务器租用价格表&#xff1a;4核16G服务器26元1个月、146元半年&#xff0c;游戏专业服务器8核32G配置90元一个月、271元3个月&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价&#xff1a; 阿里云游戏服务器租用价格表 阿…

Halcon机器视觉实战----提取水平方向缝隙区域

前言 如何从一块区域内找到水平方向的缝隙区域&#xff08;不是高斯线条&#xff0c;从图像中提取&#xff0c;而是从区域内提取&#xff0c;考虑到了区域所在的方向&#xff09;&#xff1b; dev_close_window () dev_open_window (0, 0, 800, 800, black, WindowHandle) re…

揭秘海外云手机的诸多优势

在电商领域&#xff0c;相信越来越多人听到“海外云手机”一词。尽管我们熟悉智能手机&#xff0c;但“云手机”到底是什么&#xff1f;它是如何在没有实体形态或SIM卡的情况下存在的呢&#xff1f;实际上&#xff0c;海外云手机相当于您放在国外的虚拟手机。本文将深入探讨这一…