【C++】---继承

【C++】---继承

  • 一、继承的概念及定义
    • 1、继承的概念
    • 2、定义语法格式
    • 3、继承基类成员访问方式的变化
  • 二、基类 和 派生类 的对象之间的赋值转换
    • 1、赋值规则
    • 2、切片
      • (1)子类对象 赋值 给 父类对象
      • (2)子类对象 赋值 给 父类指针
      • (3)子类对象 赋值 给 父类引用
  • 三、继承中的作用域
    • 1、父类和子类都有独立的作用域
    • 2、隐藏的概念
    • 3、如果是成员函数的隐藏,只需要函数名相同 就构成 隐藏
    • 4、继承中最好不要定义同名成员
  • 四、派生类的默认成员函数
    • 1、规则①
    • 2、规则②
    • 3、规则③
    • 4、规则④
  • 五、继承和友元
  • 六、继承和静态成员
  • 七、菱形继承
    • 1、单继承
    • 2、多继承
    • 3、菱形继承
  • 八、菱形虚拟继承
    • 1、虚继承
    • 2、虚继承的解决数据冗余 和 二义性的原理
  • 九、继承和组合

一、继承的概念及定义

1、继承的概念

继承的概念:

继承机制是面向对象程序设计当中使代码复用的重要手段,它允许程序员,在保持原有类特性的基础上,进行拓展,增加功能,产生新的类,这个新的类就叫做:派生类。

继承的出现,呈现出面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。

以前我们所接触到的复用都是函数的复用,而继承的出现则是体现了:类设计层次的复用。
在这里插入图片描述

2、定义语法格式

在这里插入图片描述

#include<iostream>
using namespace std;


// 基类
class Person
{
public:
	void Print()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age << endl;
	}
protected:
	string _name = "peter";
	int _age = 18;
};

// 派生类:stu
class Student :public Person
{
protected:
	int stu_ID;
};
// 派生类:tea
class Teacher :public Person
{
protected:
	int job_ID;
};

int main()
{
	Student s;
	Teacher t;

	s.Print();
	t.Print();

	return  0;
}

3、继承基类成员访问方式的变化

在这里插入图片描述
不需要记住总结上面的表
我给大家总结两点,只需要记住下面两点规律,一切都好说:

(1)基类private成员在派生类中无论以什么方式继承都是不可见的

(2)基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),访问权限,由大到小:public>protected>private。(Min(成员在基类的访问限定符,继承方式):意思是 取 两者访问权限较小的!)


注意:基类private成员在派生类中无论以什么方式继承都是不可见的

关于什么叫做不可见:

假如将父类成员改为private,那么子类继承了父类的私有成员,内存上,子类对象有这个成员,但是语法上不允许访问
可以理解为父类就是你的父亲,而父类的私有成员就是你父亲藏的私房钱。子类就是你自己,不可见的意思,就是说:你知道你父亲藏有私房钱,但是你找不到你见不到!

二、基类 和 派生类 的对象之间的赋值转换

1、赋值规则

(1)派生类对象可以赋值给:基类对象 / 基类的指针 / 基类的引用。这里有一个形象的说法叫做切割或者切片,就是将派生类中父类那一部分切割下来,赋值过去。(子可以给父)

(2)基类对象不能赋值给派生类对象。(父不能给子)

(3)基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTimeType Information)的dynamic_cast 来进行识别后进行安全转换。(ps:这个我们后面再讲解,这里先了解一下)

2、切片

(1)子类对象 赋值 给 父类对象

子可以赋值给父,但 父不可以赋值给子:
在这里插入图片描述

// 基类
class Person
{
public:
	void Print()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age << endl;
	}

	string _name = "peter";
	int _age = 18;
};

// 派生类:stu
class Student :public Person
{
public:
	int stu_ID;
};

int main()
{
	Student s;// s是一个 子类对象
	Person p;// p是一个 父类对象

	s._name = "yjl";
	s._age = 20;
	s.stu_ID = 20221071;

	p = s;

	s = p;
	
	return  0;
}

在这里插入图片描述

(2)子类对象 赋值 给 父类指针

在这里插入图片描述

① 子类对象可以赋值给父类指针


// 基类
class Person
{
public:
	void Print()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age << endl;
	}

	string _name = "peter";
	int _age = 18;
};

// 派生类:stu
class Student :public Person
{
public:
	int stu_ID;
};

int main()
{
	Student s;// s是一个 子类对象
	//Person p;// p是一个 父类对象

	Person* p;// p是一个 父类对象指针

	s._name = "yjl";
	s._age = 20;
	s.stu_ID = 20221071;

	p = &s;

	
	return  0;
}

在这里插入图片描述
② 若父类指针要赋值给子类指针,必须将父类指针强转为子类指针:

int main()
{
 
	//父类指针赋值给子类指针
	Person p;//父类对象
	Student *s;//子类指针
	
	p._name = "yjl";
	p._sex = "male";
	p._age = 6;
 
	Person* pp = &p;//父类指针
 
	s = (Student*)pp;//将父类指针强转为子类型指针后,再赋值给子类型指针
 
	return 0;
}

③ 指向父类对象的父类指针,强转为子类指针后赋值给子类指针可能会造成访问越界

int main()
{
	//指向父类对象的父类指针,强转为子类指针后赋值给子类指针可能会造成访问越界
	Person p;
	
	p._name = "yjl";
	p._sex = "male";
	p._age = 7;
	//s._No = 21530;
 
	Person* pp = &p;
 
	Student* ss = (Student*)pp;
	//ss->_No = 6;访问越界造成程序崩掉
 
	return 0;
}

(3)子类对象 赋值 给 父类引用

// 基类
class Person
{
public:
	void Print()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age << endl;
	}

	string _name = "peter";
	int _age = 18;
};

// 派生类:stu
class Student :public Person
{
public:
	int stu_ID;
};

int main()
{
	Student s;// s是一个 子类对象
	//Person p;// p是一个 父类对象

	//Person* p;// p是一个 父类对象指针

	

	s._name = "yjl";
	s._age = 20;
	s.stu_ID = 20221071;

	Person& p=s;// p是一个 父类对象引用

	
	return  0;
}

在这里插入图片描述

三、继承中的作用域

1、父类和子类都有独立的作用域

2、隐藏的概念

(1)子类和父类中有同名成员,子类成员将屏蔽父类,对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)

(2)通过代码来演示:隐藏!

class Person
{
public:
	string _name = "yjl";
	int _age = 20;

	void Print1()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age << endl;
	}
};

class Student :public Person
{
public:
	int _age = 100;

	void Print2()
	{
		cout << "age->" << _age << endl;
	}
};

int main()
{
	Person p;
	Student s;

	s.Print2();
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、如果是成员函数的隐藏,只需要函数名相同 就构成 隐藏

// 父类
class Person
{
public:
	string _name = "yjl";
	int _age1 = 20;

	void Print()
	{
		cout << "name->" << _name << endl;
		cout << "age->" << _age1 << endl;
	}
};
// 子类
class Student :public Person
{
public:
	int _age2 = 100;

	void Print(int count)
	{
		while (count)
		{
			cout << "age->" << _age2 << endl;
			count--;
		}
	}
};
int main()
{
	Person p;
	Student s;
	// 这里的s.Print();与父类的Print  构成函数重载×××,构成函数隐藏√√√
	// 父子类函数构成隐藏,只需要满足一点即可(函数名相同)
	s.Print();// 这里认为你用子类对象调用的是子类的打印函数,而不是你想要调用的父类打印函数。
	return 0;
}

在这里插入图片描述

4、继承中最好不要定义同名成员

四、派生类的默认成员函数

(1)什么叫做默认成员函数?

6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?

(2)派生类的默认成员函数和普通类的默认成员函数的不同区别:

  1. 派生类的构造函数必须要调用基类的构造函数来初始化基类的那一部分成员。如果基类没有写默认的构造函数,那么就必须要在派生类的初始化列表里面对基类的构造函数进行显示调用。(构造:先父后子)
  2. 派生类的拷贝构造函数必须要调用基类的拷贝构造函数,来进行对基类成员的拷贝构造。
  3. 派生类的operator=必须要调用基类的operator=完成基类的赋值
  4. 派生类的析构函数,会在被调用完成之后,自动调用基类的析构函数来清理基类的成员。因为这样才能保证析构函数作用的时候是先析构子类的成员,最后再析构父类的成员的顺序(析构:先子后父)
  5. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加显示调用的情况下,子类析构函数和父类析构函数构成隐藏关系。

总之:派生类=基类+派生类成员(①把基类看作是一个自定义类型的整体->无论是构造机构,拷贝构造,基类就调用自己的默认写的!②派生类成员看作一个普通的类!)

// 父类
class Person
{
public:
	 构造
	//Person(const char* name = "peter")
	//	:_name(name)
	//{
	//	cout << "Person()" << endl;
	//}
	 拷贝构造
	//Person(const Person& p)
	//	:_name(p._name)
	//{
	//	cout << "Person(const Person& p)" << endl;
	//}
	// 析构
	~Person()
	{
		cout << "~Person()" << endl;
	}
	// 赋值运算符重载
	Person& operator=(const Person& p)
	{
		cout << "Person& operator=()" << endl;
		if (this != &p)
		{
			_name = p._name;
		}
		return *this;
	}
protected:
	string _name;
};

// 子类
class Student :public Person
{
public:
	// 构造
	Student(const char* name,int num)
		:Person()
		,_num(num)
	{
		cout << "Student()" << endl;
	}

	// 拷贝构造
	Student(const Student& s)
		:Person(s)
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}
	// 赋值运算符重载
	Student& operator=(const Student& s)
	{
		cout << "Student& operator=" << endl;
		if (this != &s)
		{
			Person::operator=(s);
			_num = s._num;
		}
		return *this;
	}
	// 析构
	~Student()
	{
		cout << "~Student()" << endl;
	}
protected:
	int _num;// 学号
};


void test()
{
	Person p1;

	Student s1("yjl", 2022);
	//Student s2("yjl666", 2024);

	//Student s3(s1);

	//Person p2(s3);

}

int main()
{
	test();

	return 0;
}

1、规则①

规则①:子类的构造函数必须调用父类的构造函数初始化父类的那一部分成员。如果父类没有默认的构造函数,则必须在子类构造函数的初始化列表阶段显式调用。

(1)回忆一下什么是默认构造函数?

  1. 我们没有写编译器,自动生成的。
  2. 我们自己写了无参的构造函数。
  3. 我们自己写了的,带参的全缺省构造函数。

(2)父类里面没有写默认的构造函数和拷贝构造函数:
在这里插入图片描述
当父类没有写默认的构造函数的时候,显式调用父类默认构造函数,是把当作一个整体去调父类的构造函数!
(3)父类里面写了默认的构造函数:

在这里插入图片描述
总结:
(1)父类有默认构造函数,子类只需要在构造函数中初始化子类自己的成员
(2)父类没有默认构造函数,子类要在构造函数初始化列表显式调用父类的构造函数,再初始化子类自己的成员

2、规则②

规则②:子类的拷贝构造函数必须调用父类的拷贝构造完成父类的拷贝初始化。

子类的拷贝构造函数该如何写呢?

调用父类拷贝构造函数时,将子类对象作为参数传给父类拷贝构造函数,这时会发生切片行为,将子类对象中父类成员部分切片赋值给父类成员,完成父类拷贝构造;再将子类自己的成员初始化为拷贝对象的子类成员值:

3、规则③

规则③ 子类的operator=必须要调用父类的operator=完成父类的赋值

如果子类的赋值运算符重载函数里只调用子类的operator=,那么会发生栈溢出:

// 赋值运算符重载
	Student& operator=(const Student& s)
	{
		cout << "Student& operator=" << endl;
		if (this != &s)
		{
			operator=(s);
			_num = s._num;
		}
		return *this;
	}

void test()
{
	//Person p1;

	Student s1("yjl", 2022);
	Student s2("yjl666", 2024);

	s1 = s2;// 赋值的时候,会发生:栈溢出

	//Person p2(s3);

}

在这里插入图片描述
这样写才对:

	// 赋值运算符重载
	Student& operator=(const Student& s)
	{
		cout << "Student& operator=" << endl;
		if (this != &s)
		{
			Person::operator=(s);
			_num = s._num;
		}
		return *this;
	}

4、规则④

规则④ 子类的析构函数会在被调用完成后自动调用父类的析构函数清理父类成员。因为这样才能保证子类对象先清理子类成员再清理父类成员的顺序
1、
(1)析构顺序:先子后父!

(2)构造顺序:先父后子!

在这里插入图片描述
2、注意:由于多态的缘故,对析构的统一处理

// 对析构的统一处理:
	~Student()
	{
		//Person::~Person();
		~Person();
		cout << "~Student()" << endl;
	}

在这里插入图片描述
这是由于父类的析构函数和子类的析构函数构成隐藏,奇不奇怪?

按照隐藏的定义,父类和子类的同名函数才会构成隐藏,为什么父类和子类的析构函数不同名也会构成隐藏呢?

这是因为多态的缘故,任何类的析构函数名都会被统一处理成destructor( )。所以父类和子类析构函数同名,会构成隐藏。解决方法就是加父类作用域,指定访问的是父类的析构函数就可以了:

	// 析构
	~Student()
	{
		Person::~Person();
		//~Person();
		cout << "~Student()" << endl;
	}

在这里插入图片描述

五、继承和友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员

class Student;
class Person
{
public:
 friend void Display(const Person& p, const Student& s);
protected:
 string _name; // 姓名
};
class Student : public Person
{
protected:
 int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
 cout << p._name << endl;
 cout << s._stuNum << endl;
}
void main()
{
 Person p;
 Student s;
 Display(p, s);
}

六、继承和静态成员

如果在父类里面定义了一个static静态成员,那么在整个继承体系当中,无论父类派生出多少个子类,整个体系只有这一个静态成员!

下面这些代码是对静态成员变量的诠释,在整个继承体系中,只要有static静态成员变量,那么它就是同一个!

#include<iostream>

using namespace std;

class Person
{
public:
	Person() { _count++; }
protected:
	string _name;
public:
	static int _count;
};

int Person::_count = 0;

class Student : public Person
{
protected:
	int _ID;
};

class Graduate : public Student
{
protected:
	string _course;
};


void TestPerson()
{
	Student s1;
	Student s2;
	Student s3;

	Graduate s4;// 在上面的继承体系中,它是单继承。
	// 创建子类对象的时候必须要先构造父类对象,所以进行到此处_count等于4。
	cout << "人数:" << Person::_count << endl;
	Student::_count = 0;// 因为已经说明了_count是一个静态的,在整个继承体系中它就是一个整体就是一个
	// 对_count修改后他就是0了。
	cout << "人数:" << Person::_count << endl;
}

int main()
{
	TestPerson();
	return 0;
}

在这里插入图片描述

七、菱形继承

1、单继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

在这里插入图片描述

2、多继承

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

在这里插入图片描述

3、菱形继承

菱形继承:菱形继承是多继承的一种特殊情况。

在这里插入图片描述

class Person
{
public:
	string _name;
};

class Student : public Person
{
protected:
	int _num;
};

class Teacher : public Person
{
protected:
	int _id;
};

class Assistant :public Student, public Teacher
{
protected:
	string _course;
};

void Test()
{
	Assistant a;
	a._name = "peter";// 这样会有二义性无法明确知道访问的是哪一个_name
	// 因为,a访问的_name没有指明是student继承person的_name,还是teacher继承person的_name。

	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "xxx";
}

菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。
在Assistant的对象中Person成员会有两份。

在这里插入图片描述

八、菱形虚拟继承

虚拟继承:可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。
需要注意的是,虚拟继承不要在其他地方去使用。

1、虚继承

虚继承的语法格式:在两个直接父类的继承方式访问限定符前加vitual:

class Person
{
public:
	string _name;
};

class Student : virtual public Person
{
protected:
	int _num;
};

class Teacher : virtual public Person
{
protected:
	int _id;
};

class Assistant :public Student, public Teacher
{
protected:
	string _course;
};

void Test()
{
	Assistant a;
	a._name = "peter";

	/*a.Student::_name = "xxx";
	a.Teacher::_name = "xxx";*/
}

int main()
{
	Test();
	return 0;
}

在这里插入图片描述

2、虚继承的解决数据冗余 和 二义性的原理

虚拟继承解决数据冗余和二义性的原理:

为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系,再借助内存窗口观察对象成员的模型

class A
{
public:
 int _a;
};
// class B : public A
class B : virtual public A
{
public:
 int _b;
};
// class C : public A
class C : virtual public A
{
public:
 int _c;
};
class D : public B, public C
{
public:
 int _d;
};
int main()
{
 D d;
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;
 return 0;
}

下图是菱形继承的内存对象成员模型:这里可以看到数据冗余:
在这里插入图片描述

下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。

在这里插入图片描述
下面是上面的Person关系菱形虚拟继承的原理解释:

在这里插入图片描述

九、继承和组合

  1. 很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设计出菱形继承。否则在复杂度及性能上都有问题。
  2. 多继承可以认为是C++的缺陷之一,很多后来的OO语言都没有多继承,如Java。
  3. 继承和组合:

(1)public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。

(2)组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。

(3)优先使用对象组合,而不是类继承 :链接:优先使用对象组合,而不是类继承

(4)实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用
继承,可以用组合,就用组合。

// Car和BMW Car和Benz构成is-a的关系
   class Car{
   protected:
   string _colour = "白色"; // 颜色
   string _num = "陕ABIT00"; // 车牌号
   };
   
   class BMW : public Car{
   public:
   void Drive() {cout << "好开-操控" << endl;}
   };
   
   class Benz : public Car{
   public:
   void Drive() {cout << "好坐-舒适" << endl;}
   };
   
   // Tire和Car构成has-a的关系
   
   class Tire{
   protected:
       string _brand = "Michelin";  // 品牌
       size_t _size = 17;         // 尺寸
   
   };
   
   class Car{
   protected:
   string _colour = "白色"; // 颜色
   string _num = "陕ABIT00"; // 车牌号
    Tire _t; // 轮胎
   };

好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

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

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

相关文章

windows11忘记登录密码怎么办?

STEP1&#xff1a;进入Win RE界面 1.按住shift不要松手,点击重新启动&#xff0c;进入WINRE界面 2.选择疑难解答 选择高级选项 点击命令提示符 STEP2:替换utilman 1.输入以下代码查看所在windows所在盘 diskpart list volume exit 2.根据所在盘输入命令&#xff08;以C盘为…

数据结构与算法(5)队列的基本操作

#include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int ElemType; #define MaxSize 10//队列的定义 typedef struct SqQueue {ElemType data[MaxSize];int front, rear;//front为头指针&#xff0c;rear为尾指针。这里并不是真正的“指针”…

Java | Spring框架 | @Autowired与@Resource

在Spring框架中&#xff0c;依赖注入是一种核心概念&#xff0c;它允许开发者将对象的创建和对象之间的依赖关系的管理交给框架来处理。这样做的目的是为了提高代码的模块化和可测试性。 Spring提供了多种方式来实现依赖注入&#xff0c;其中最常用的方式是通过注解。在本文中…

mysql数据库---操作数据库跟表的命令总结

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文着重整理mysql管理库跟表的指令。 不涉及增删查改等指令 其实本篇主要是我做好笔记格式 用的时候直接复制粘贴的 所以排版大多是为了快速找功能来排的 方便大家快速找目标语法 数据库的简介 一个数据库系…

[Redis] 使用布隆过滤器和分布式锁实现用户注册

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于快速判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来表示一个集合&#xff0c;当一个元素被加入到集合时&#xff0c;通过哈希函数计算出多个哈希值&#xff0c;并…

Hypack 2024 简体中文资源完整翻译汉化已经全部完成

Hypack 2024 简体中文资源完整翻译汉化已经全部完成 Hypack 2024&#xff0c;资源汉化共翻译11065条。毕竟涉及测绘、水文、疏浚等专业术语太多&#xff0c;翻译有很多理解不正确的地方&#xff0c;望各位专业人员指正。 压缩包内包含Hypack 2024、Hypack 2022、Hypack 2021、…

什么样的行业适合做私域?

私域营销适用于各种行业&#xff0c;但以下几个行业尤其适合进行私域营销&#xff1a; 1、零售行业&#xff1a;私域营销可以帮助零售企业建立与顾客的直接联系&#xff0c;提高顾客忠诚度和复购率。通过私域营销&#xff0c;零售企业可以进行个性化推荐、定制化服务&#xff…

JavaWeb--11MySQL(3)-- 多表设计

MySQL&#xff08;3&#xff09;-- 多表设计 1 一对多&#xff08;多对一&#xff09;2 一对一3 多对多 各个表结构之间也存在着各种联系&#xff0c;基本上分为三种&#xff1a; 一对多(多对一)多对多一对一 1 一对多&#xff08;多对一&#xff09; 一对多关系实现&#x…

【Java】IO流:字节流 字符流 缓冲流

接续上文&#xff0c;在这篇文章将继续介绍在Java中关于文件操作的一些内容【Java】文件操作 文章目录 一、“流”的概念1.“流”的分类1.1输入流和输出流1.2字节流和字符流 字节和字符的区别&#xff1f;为什么要有字符流&#xff1f;1.3节点流和处理流 字符流自带缓冲区&…

【Linux——Centos7安装RabbitMQ】 RabbitMQ无法连接

到这一步是基本已经装好了&#xff0c;现在是在开放端口&#xff0c;我这个报错是因为我的防火墙是处于关闭状态&#xff0c;所以在开放端口时会报防火墙为运行&#xff0c;把防火墙打开&#xff0c;在开放端口&#xff0c;就可以访问到了 重启防火墙&#xff1a; systemctl …

【无标题】基于GIS、Python机器学习技术的地质灾害风险评价、易发性分析与信息化建库及灾后重建中的实践技术

理解地质灾害形成机理与成灾模式&#xff1b;从空间数据处理、信息化指标空间数据库构建、致灾因子提取&#xff0c;空间分析、危险性评价与制图分析等方面掌握GIS在灾害危险性评价中的方法&#xff1b;运用地质灾害危险性评价原理和技术方法 原文链接&#xff1a;基于GIS、Py…

DeepSeek API文档:创建对话补全的指南

DeepSeek平台不仅提供了一个用户友好的聊天界面&#xff0c;还为开发者提供了强大的API接口&#xff0c;使他们能够创建和集成智能对话补全功能。以下是关于如何使用DeepSeek API创建对话补全的详细介绍。 DeepSeek API概述 DeepSeek的API允许开发者通过编程方式与DeepSeek的…

应用软件安全保证措施方案书

系统安全保证措施方案—word原件 软件全套资料进主页获取或者本文末个人名片直接获取。

【文章转载】ChatGPT 提示词十级技巧: 从新手到专家

学习了微博网友宝玉xp老师《ChatGPT 提示词十级技巧: 从新手到专家》 个人学习要点&#xff1a; 1、关于提示中避免使用否定句&#xff0c;播主说&#xff1a;“没有人能准确解释为什么&#xff0c;但大语言模型在你告诉它去做某事时&#xff0c;表现似乎比你让它不做某事时更…

识货小程序逆向

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872&#xff0c;x30184483x…

Java进阶07集合(续)

Java进阶07 集合&#xff08;续&#xff09; 一、数据结构&#xff08;树&#xff09; 1、关于树 1.1 相关概念 节点&#xff1a;树中每个单独的分支 节点的度&#xff1a;每个节点的子节点数量 树高&#xff1a;树的总层数 根节点&#xff1a;最顶层节点 左子节点&…

6层板学习笔记2

说明:笔记基于6层全志H3消费电子0.65MM间距BGA 67、多层板的电源建议直接大面积铺铜,不建议走线,铺铜充分满足其载流能力 68、凡亿推荐表层1OZ的铜厚线宽20MIL能承载1A的电流,内层0.5OZ的铜厚线宽为40MIL能承载1A的电流,过孔直径20MIL(0.5MM)能承载1A左右的电流,实际设…

typescript的入门到吐槽:看了typescript,发现前端真的卷,

typescript TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集&#xff0c;而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。 TypeScript 与 JavaScript 的区别 其实就是对JavaScript的封装&#xff0c;把一个弱类型语言封…

remmina无法连接远程桌面,Remmina无法连接远程桌面的原因与解决办法

在解决Remmina无法连接远程桌面的问题时&#xff0c;我们需要考虑多种可能的原因&#xff0c;并采取相应的解决办法。以下是一些常见的原因及其对应的解决方案&#xff1a; 1、网络问题 原因&#xff1a;不稳定的网络连接或中断可能导致无法建立远程桌面连接。 解决办法&#x…

MySQL数据库---增删查改汇总

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文着重整理MySQL数据库增删查改功能 主要是整理语法 争取做到要用什么语法 可以快速找到复制粘贴 增添语法 INSERT into tab(列名,列名,列名) values(内容,内容,内容); 插入一行数据 INSERT into tab(列名,…
最新文章