【C++初阶】类与对象(三)

news2024/11/17 15:32:03

目录

  • 一、再谈构造函数
    • 1.1 初始化列表
      • 1.1.1 初始化列表写法
      • 1.1.2 哪些成员要使用初始化列表
    • 1.2 初始化列表的特点
      • 1.2.1 队列类问题解决
      • 1.2.2 声明顺序是初始化列表的顺序
    • 1.3 explicit关键字
      • 1.3.1 explicit关键字的作用
  • 二、static成员
    • 2.1 类的静态成员概念
    • 2.2 类里创建了多少个对象问题
  • 三、友元
    • 3.1 概念
    • 3.2 友元函数
    • 3.3 友元类
  • 四、内部类
  • 五、拷贝对象时的一些编译器优化

一、再谈构造函数

1.1 初始化列表

构造函数之前我们已经学过大部分内容,但是并没有学全,还有一个很重要的东西——初始化列表

1.1.1 初始化列表写法

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

	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
	
	}
	//
	Date d1(2023, 11, 9);

运行结果:
在这里插入图片描述
括号里也可以是数值(没有传参的情况):

	Date()
		:_year(2023)
		, _month(11)
		, _day(9)
	{

	}

补充:声明给缺省值其实是给初始化列表的,但是在没显示写构造函数的情况;如果有写构造函数的话用构造函数中定义的值,构造函数没有参数或者具体数值就是随机值。(VS下随机值是0)

1.1.2 哪些成员要使用初始化列表

先总结下,再逐一分析

一定要初始化列表的成员有:
1.引用成员变量
2.const成员变量
3.没有默认构造的自定义类型成员变量

public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
		,t(year)
		,a(5)
	{

	}

private:
	int _year;
	int _month;
	int _day;
	int& t;//引用成员变量
	const int a;//const成员变量
};

运行结果:
在这里插入图片描述

1️⃣使用引用有一个规定,那就是必须初始化。而在以上没有初始化是因为这些都是声明,接下来要定义这个引用成员变量,那么定义的地方在哪?就在初始化列表。

2️⃣const成员变量与引用也是一样的,在私有的区域里只是声明,要定义的话必须在初始化列表。

3️⃣上篇文章使用队列类的时候我们没有写队列类的构造函数,内置类型声明有缺省值使用缺省值,没有是随机值;自定义类型成员变量让编译器自动调用它的默认构造。

复习下什么是默认构造:
1.我们不显示写构造函数编译器默认自动生成的
2.没有传参的
3.全缺省的

如果我们要自己控制参数为多少,也就是说要传参给自定义类型的构造函数(或者自定义类型的构造函数不是默认构造,就要我们自己传参,否则我们既没有显示队列类的构造函数,也没有把它的自定义类型的构造为默认构造,结果就为随机值),就必须显示写构造函数初始化,构造函数要有初始化列表

总结一下:
引用成员变量和const成员变量必须要在定义的地方初始化,这个地方在初始化列表;自定义类型成员变量不写这个类的构造函数,自动调用这个自定义类型成员的默认构造;写这个类的构造函数,下面接着分析~~

1.2 初始化列表的特点

1.2.1 队列类问题解决

之前我们不写队列类的构造函数,这次就要写,构造函数里初始化自定义类型的成员变量,要用初始化列表解决。

以下代码:

class Stack
{
public:
	Stack(int capacity = 3)
	{
		cout << "Stack(int capacity = 3)" << endl;
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == NULL)
		{
			perror("malloc fail");
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = NULL;
		_top = 0;
		_capacity = 0;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};
class Queue
{
public:
//   队列类的构造函数
	Queue()
		:_st1()
		,_st2()
		,_size()
	{

	}
private:

	Stack _st1;
	Stack _st2;
	int _size;
};
int main()
{
	Queue q1;
	return 0;
}

参数是谁,有几种情况:
1️⃣只有构造函数,没有参数、括号后没有具体值
通过调试查看允许结果:
在这里插入图片描述
我们发现是0、3、0、3、0,所以在没有传任何值的情况下,初始化列表里对于内置类型是随机值(VS下变成0),自定义类型调用它的默认构造

2️⃣没有参数、括号后有具体值

	Queue()
		:_st1(10)
		, _st2(20)
		, _size(30)
	{

	}

调试结果:
在这里插入图片描述

3️⃣有参数为全缺省、括号后有具体值

	Queue(Stack st1 = 44, Stack st2 = 66, int size = 88)
		:_st1(1)
		, _st2(2)
		, _size(3)
	{

	}

调试结果:
在这里插入图片描述
4️⃣有参数为全缺省、括号后为参数

	Queue(Stack st1 = 44, Stack st2 = 66, int size = 88)
		:_st1(st1)
		, _st2(st2)
		, _size(size)
	{

	}

调试结果:
在这里插入图片描述

5️⃣自己传参

	Queue(Stack st1 = 44, Stack st2 = 66, int size = 88)
		:_st1(st1)
		, _st2(st2)
		, _size(size)
	{

	}
	///
	Queue q1(11, 77, 99);

调试结果:
在这里插入图片描述
6️⃣没有构造函数,声明给缺省值

private:
	Stack _st1 = 7;
	Stack _st2 = 8;
	int _size = 9;
};

调试结果:
在这里插入图片描述

总结一下:
1.当自定义类型成员的构造函数不是默认构造,有以下
自己传参5️⃣;有参数为全缺省、括号后为参数4️⃣;有参数为全缺省、括号后有具体值3️⃣;没有参数、括号后有具体值2️⃣;声明给缺省值6️⃣。总之就是有给自定义类型成员的构造函数传参
有具体值就用具体值,没有具体值自己传参优先,其次缺省值
为了方便控制参数,所以使用5️⃣较好。
2.当自定义类型成员的构造函数是默认构造:
只有构造函数、没有参数、没有具体值1️⃣
还有第七种7️⃣不写构造函数(上篇文章的写法)
这两种其实没有区别,所以干脆不写构造函数。

1.2.2 声明顺序是初始化列表的顺序

直接用例子展示:

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

	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _day;//day放在最前面
	int _year;
	int _month;
};
int main()
{
	Date d1(2023, 11, 9);
	d1.Print();
	return 0;
}

调试结果:
在这里插入图片描述
所以天最先被初始化,其次是年和月。

1.3 explicit关键字

1.3.1 explicit关键字的作用

对于只有内置类型的单参数的构造函数,具有类型转换的功能
看以下代码:

class A
{
public:
	A(int a)
	{
		_a = a;
	}
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A aa(1);
	aa = 3;
	aa.Print();
	return 0;
}

aa是自定义类型,3是整型,运行结果:
在这里插入图片描述
如果不想转换发生,构造函数前加explicit,此时编译器会有报错提示。

补充:加explicit关键字可以阻止隐式类型转换,但不能阻止强转。

没有使用explicit修饰,多参数且是半缺省也支持。

class Date
{
public:
	Date(int year, int month = 2, int day = 3)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1 = (2023, 11, 10);
	return 0;
}

调试结果:
在这里插入图片描述
注意:小括号是逗号表达式,只算最后一个数,其他的是缺省值。

修改一下,把小括号变成花括号,并且不要缺省值:

Date d1 = { 2023, 11, 10 };

调试结果:
在这里插入图片描述

二、static成员

2.1 类的静态成员概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。

2.2 类里创建了多少个对象问题

定义一个变量count用来计数,每创建(构造)一个对象,或者拷贝构造一个对象,count++。我们先用全局变量count来计数,看会发生什么:
1️⃣

int count = 0;
class A
{
public:
	A() { ++count; }
	A(const A& t) { ++count; }
	~A() {  }
private:

};

A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa;
	Func();
	cout << count << endl;
	return 0;
}

在这里插入图片描述
编译器报错了,提示count为不明确的符号,说明命名冲突了。

命名冲突的解决办法——命名空间
2️⃣

namespace yss
{
	int count = 0;
}
class A
{
public:
	A() { ++yss::count; }
	A(const A& t) { ++yss::count; }
	~A() {  }

private:
	
};

A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa;
	Func();
	cout << yss::count << endl;
	return 0;
}

运行结果:
在这里插入图片描述
这个结果确实是我们要的答案,但是这里却有一个问题:如果再多一个类,使用全局变量就不能把两个类区分开来,导致计数完一个类再去计数另一个类count的值没有更新,也就是说两个类的对象是合并在一起的。

我们换一种方式,定义类的成员变量
3️⃣

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

//private:
	int count = 0;
};

A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa;
	Func();
	cout << aa.count << endl;
	return 0;
}

我们暂时把私有的权限注释掉,看看运行结果如何:
在这里插入图片描述
为什么会是1呢?因为每创建一个对象,count+1,但是又创建一个对象,count清零再+1。说明类里一个对象一个count,而我们要的结果是类里的所有对象的个数,可是每个对象有自己的count。

要让类里的对象都是一个count怎么办,使用静态成员变量,static修饰count。
静态成员变量一定要在类外进行初始化
4️⃣

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

//private:
	static int count;
};
int A::count = 0;
A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa;
	Func();
	cout << aa.count << endl;
	return 0;
}

运行结果:
在这里插入图片描述
结果没问题了,但是,没有私有的权限,类的封装性就不能很好了。

改进:可通过一个成员函数来返回count的值
5️⃣

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

	int Getcount()
	{
		return count;
	}
private:
	static int count;
};
int A::count = 0;
A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa;
	Func();
	cout << aa.Getcount() << endl;
	return 0;
}

运行结果:
在这里插入图片描述
但是如果我们想通过调用Func函数来计数对象创建了几个,main函数里实例化的对象不算该怎么办?

假设调用两次Func函数,先别注释对象的实例化,得到的结果应该为5

int main()
{
	A aa;
	Func();
	Func();
	cout << aa.Getcount() << endl;
	return 0;
}

在这里插入图片描述
然后把对象注释掉,发现编译器报错:未定义标识符aa。
在这里插入图片描述

可以使用静态成员函数来解决
6️⃣

	static int Getcount()
	{
		return count;
	}

注意:要通过类名::静态成员来访问

运行结果:
在这里插入图片描述

总结:
静态成员变量和静态成员函数与全局变量和全局函数很像,只是受作用域限定符和点成员操作符限制
补充:
静态成员函数不可以调用非静态成员函数,因为静态成员函数没有this指针; 非静态成员函数可以调用类的静态成员函数,因为它们属于同一个类。

三、友元

3.1 概念

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

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

3.2 友元函数

当一个函数不是类的成员函数,但又要能访问到类里的成员变量,必须使用友元函数

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

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//友元函数
	friend ostream& operator<<(ostream& out, Date& d);
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}
int main()
{
	Date d1(2023, 11, 10);
	cout << d1;
	return 0;
}

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

3.3 友元类

创建一个时间类,声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量

class Time
{
	// 友元类
	friend class Date; 
public:
	Time(int hour = 2020, int minute = 6, int second = 5)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{}

private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
	Date(int year = 2023, int month = 11, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
		Print();
	}
	void Print()
	{
		cout << _t._hour << "-" << _t._minute << "-" << _t._second << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main()
{
	Date d1;
	d1.Print();
	return 0;
}

在这里插入图片描述

特点:
友元关系是单向的,不具有交换性
在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元。
友元关系不能继承

四、内部类

一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。

内部类就是外部类的友元类。内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

class A
{
public:
	class B
	{
	public:
		void Func()
		{
			cout << _a << endl;
		}
	};
	private:
		int _b;
private:
	static int _a;
};
int A::_a = 10;
int main()
{
	A::B b1;
	b1.Func();
	return 0;
}

在这里插入图片描述

特点:
内部类可以定义在外部类的public、protected、private都是可以的
注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名
sizeof(外部类)=外部类,和内部类没有任何关系

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

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝。不同的编译器优化的方式可能会不同。

1️⃣隐式类型,连续构造+拷贝构造->优化为直接构造

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;
	}
private:
	int _a;
};
void Func(A aa)
{
	
}
int main()
{
	Func(1);
	return 0;
}

在这里插入图片描述
1是整型,发生隐式类型转换通过调用构造函数产生临时变量,临时变量再拷贝给形参调用拷贝构造函数。

2️⃣一个表达式中,连续构造+拷贝构造->优化为一个构造

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;
	}
private:
	int _a;
};
void Func(A aa)
{

}
int main()
{
	Func(A(1));
	return 0;
}

在这里插入图片描述
在一个表达式中,A(1)调用构造函数产生临时变量,临时变量再拷贝给形参调用拷贝构造函数,优化成一次构造。

3️⃣一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造

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;
	}
private:
	int _a;
};
A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa2 = Func();
	return 0;
}

在这里插入图片描述
实例化aa2调用一次构造,进入Func()函数,创建aa对象调用一次构造,两次构造优化为一次构造;局部变量拷贝给返回值调用拷贝构造,返回值拷贝给aa2再调用拷贝构造,两次拷贝构造优化成一次拷贝构造。

4️⃣一个表达式中,连续拷贝构造+赋值重载->无法优化

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;
	}
private:
	int _a;
};
A Func()
{
	A aa;
	return aa;
}
int main()
{
	A aa3;
	aa3 = Func();
	return 0;
}

在这里插入图片描述
实例化aa3调用构造,此时aa3已存在,调用Func()的返回值是赋值,Func()函数里创建aa对象调用构造,局部变量拷贝给返回值调用拷贝构造,最后赋值。

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

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

相关文章

C++ 模板保姆级详解——template<class T>(什么是模板?模板分哪几类?模板如何应用?)

目录 一、前言 二、 什么是C模板 &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、函数模板 &#x1f4a6;函数模板概念 &#x1f4a6;函数模板格式 &#x1f4a6;函数模板的原理 &#x1f4a6;函数模板的实例化 &#x1f34e;隐式实例化 &#x1f349;显式实…

Halcon WPF 开发学习笔记(4):Halcon 锚点坐标打印

文章目录 专栏前言锚点二次开发添加回调函数辅助Model类 下集预告 专栏 Halcon开发 博客专栏 WPF/HALCON机器视觉合集 前言 Halcon控件C#开发是我们必须掌握的&#xff0c;因为只是单纯的引用脚本灵活性过低&#xff0c;我们要拥有Halcon辅助开发的能力 锚点开发是我们常用的…

记录一次某某虚拟机的逆向

导语 学了一段时间的XPosed&#xff0c;发现XPosed真的好强&#xff0c;只要技术强&#xff0c;什么操作都能实现... 这次主要记录一下我对这款应用的逆向思路 apk检查 使用MT管理器检查apk的加壳情况 发现是某数字的免费版本 直接使用frida-dexdump 脱下来后备用 应用分…

【ATTCK】MITRE Caldera - 测试数据泄露技巧

CALDERA是一个由python语言编写的红蓝对抗工具&#xff08;攻击模拟工具&#xff09;。它是MITRE公司发起的一个研究项目&#xff0c;该工具的攻击流程是建立在ATT&CK攻击行为模型和知识库之上的&#xff0c;能够较真实地APT攻击行为模式。 通过CALDERA工具&#xff0c;安全…

Git版本控制系统之分支与标签(版本)

目录 一、Git分支&#xff08;Branch&#xff09; 1.1 分支作用 1.2 四种分支管理策略 1.3 使用案例 1.3.1 指令 1.3.2 结合应用场景使用 二、Git标签&#xff08;Tag&#xff09; 2.1 标签作用 2.2 标签规范 2.3 使用案例 2.3.1 指令 2.3.2 使用示例 一、Git分支&…

55基于matlab的1.高斯噪声2.瑞利噪声3.伽马噪声4.均匀分布噪声5.脉冲(椒盐)噪声

基于matlab的1.高斯噪声2.瑞利噪声3.伽马噪声4.均匀分布噪声5.脉冲&#xff08;椒盐&#xff09;噪声五组噪声模型&#xff0c;程序已调通&#xff0c;可直接运行。 55高斯噪声、瑞利噪声 (xiaohongshu.com)

“第六十六天”

这个我记得是有更优解的&#xff0c;不过还是明天发吧&#xff0c;明天想一想&#xff0c;看看能不能想起来 #include<string.h> int main() {char a[201] { 0 };char b[201] { 0 };scanf("%s %s", a, b);int na strlen(a);int nb strlen(b);int i 0, j …

基于SpringBoot+Vue的在线学习平台系统

基于SpringBootVue的在线学习平台系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 用户界面 登录界面 管理员界面 摘要 本文设计并实现了一套基于Spri…

C语言——贪吃蛇

一. 游戏效果 贪吃蛇 二. 游戏背景 贪吃蛇是久负盛名的游戏&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的⾏列。 贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》&#xff0c;后移植到各种平台上。具体如下&#xff1a; 起源。1977年&#xff0c;投币式…

Leetcode421. 数组中两个数的最大异或值

Every day a Leetcode 题目来源&#xff1a;421. 数组中两个数的最大异或值 解法1&#xff1a;贪心 位运算 初始化答案 ans 0。从最高位 high_bit 开始枚举 i&#xff0c;也就是 max⁡(nums) 的二进制长度减一。设 newAns ans 2i&#xff0c;看能否从数组 nums 中选两个…

数据结构—二叉树的模拟实现(c语言)

目录 一.前言 二.模拟实现链式结构的二叉树 2.1二叉树的底层结构 2.2通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 2.3二叉树的销毁 2.4二叉树查找值为x的节点 2.5二叉树节点个数 2.6二叉树叶子节点个数 2.7二叉树第k层节点个数 三.二叉树的遍历 3.1…

基于SpringMVC模式的电器网上订购系统的设计

大家好我是玥沐春风&#xff0c;今天分享一个基于SpringMVC模式的电器网上订购系统的设计&#xff0c;项目源码以及部署相关请联系我&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 本系统利用现在比较广泛的JSP结合后台SpringMybatisAjax编写程序的方式实现的。 在…

深度学习基于python+TensorFlow+Django的花朵识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 花朵识别系统&#xff0c;基于Python实现&#xff0c;深度学习卷积神经网络&#xff0c;通过TensorFlow搭建卷积神经…

Think-on-Graph:基于知识图的大型语言模型的深层可靠推理11.12

Hink-on-Graph&#xff1a;基于知识图的大型语言模型的深层可靠推理 摘要1 引言2 方法2.1图上思考2.1.1图的初始化2.1.2 探索2.1.3推理 2.2 基于关系的Think on graph 摘要 尽管大型语言模型&#xff08;LLM&#xff09;在各种任务中取得了巨大的成功&#xff0c;但它们经常与…

jupyter lab配置列表清单

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【 第十章】软件设计师 之 软件工程概述

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 备考资料导航 软考好处&#xff1a;软考的…

“总线仲裁”——以CAN总线为例

总线仲裁 1.什么是总线仲裁2.为什么要总线仲裁3.怎么进行总线仲裁&#xff08;总线仲裁机制&#xff09;3.1 如何确定冲突3.1.1 确定冲突前提3.1.2 同时冲突3.1.3 延时冲突 3.2 冲裁逻辑3.2.1 避免延时冲突3.2.1 避免同时冲突 1.什么是总线仲裁 提到总线仲裁的概念&#xff0c…

基于Qt 多线程(继承自QThread篇)

# 简介 我们写的一个应用程序,应用程序跑起来后一般情况下只有一个线程,但是可能也有特殊情况。比如我们前面章节写的例程都跑起来后只有一个线程,就是程序的主线程。线程内的操作都是顺序执行的。恩,顺序执行?试着想一下,我们的程序顺序执行,假设我们的用户界面点击有某…

leetcode-链表经典题

1.反转单链表 206. 反转链表https://leetcode.cn/problems/reverse-linked-list/这里我们使用创建一个变量cur来遍历原链表&#xff0c;再创建一个新节点newnode&#xff0c;首先使用一个循环来遍历原链表&#xff0c;cur为NULL是循环结束&#xff0c;每次进入循环将cur的下一…