6-继承

6-继承

  • 1、基本语法和方式
  • 2、继承的基本特点
    • 2.1 三种继承方式相同的基本点
    • 2.2 三种继承方式的差别
    • 2.3 公有继承的独有特点
  • 3、子类的构造、析构
    • 3.1 子类的构造
    • 3.2 子类的析构
    • 3.3 子类的拷贝构造函数
    • 3.4 子类的拷贝赋值
  • 4、多重继承
    • 4.1 内存布局
    • 4.2 类型转换
    • 4.3 名字冲突问题
  • 5、砖石继承
  • 6、虚继承

1、基本语法和方式

class 子类 : 继承方式1 基类1, 继承方式2 基类2, ... {
	...
};
  • 继承方式
    公有继承:public
    保护继承:protected
    私有继承:private

2、继承的基本特点

2.1 三种继承方式相同的基本点

  • 继承所要达到的目的:
    • 子类对象包含基类子对象
    • 子类内部可以直接访问基类的所有非私有成员
  • 继承的本质:
    • 基类的非私有成员在子类中仅仅为可见,而非拥有
      注意:
      对于继承切忌不要理解为基类的成员变为子类的成员,继承不会改变类成员的作用域,基类的成员永远都是基类的成员,并不会因为继承而变成子类的成员
  • 尽管基类的公有和保护成员在子类中直接可见,但仍然可以在子类中重新定义这些名字,子类中的名字会隐藏所有基类中的同名定义
  • 如果需要在子类内部访问 一个在基类中定义却被子类标识符所隐藏的名字,可以借助作用域限定操作符“::”实现
  • 因为作用域的不同,分别在子类和基类中定义的同名成员函数(包括静态成员函数),并不构成重载关系,相反是一种隐藏关系
  • 任何时候,在子类的内部,总可以通过作用域限定操作符“::”,显式地调用那些在基类中定义却被子类所隐藏的成员
// 继承最基本的特点
// (1) 子类对象的内部 包含 基类子对象
// (2) 子类内部可以直接访问 基类的 非私有(共有/保护)成员(变量/函数)
// (3) 一旦被子类同名定义隐藏 可以借助::指明访问基类
class Base{
public:
	int m_a;
	void foo(){ cout << "Base::foo" << endl; }
protected:
	int m_b;
	void bar(){ cout << "Base::Bar" << endl; }
private:
	int m_c;
	void hum(){ cout << "Base::hum" << endl; }
};
class Derived :public Base{
public:
	void fun(){
		m_a = 100;
		Base::foo();// 子类的foo函数将基类的foo函数隐藏,但可以通过作用域限定符访问基类的foo
		m_b = 100;
		bar();  //子类内部可以直接访问 基类的 非私有(共有/保护)成员(变量/函数)
		//m_c = 100;
		//hum();
	}
private:
	int m_d;
	void foo(){ cout << "Derived::foo" << endl; }
	void bar(){ cout << "Derived::Bar" << endl; }
};
int main(){
	Base b;// 基类对象
	cout << "基类对象b的大小" << sizeof(b) << endl; // 12
	Derived d;// 子类对象
	cout << "子类对象d的大小" << sizeof(d) << endl; // 16  子类对象的内部 包含 基类子对象
	d.fun();
	return 0;
}

2.2 三种继承方式的差别

  • 基类中的公有、保护和私有成员,在子类中将对这些基类成员的访问控制限定进行重新标记
// public继承的独特点
class publicBase :public Base{// 子类将对基类的成员重新标记访问限定符
	// 子类将对基类的成员重新标记访控限定 m_a/foo是public m_b/bar是protected m_c/hum是private
public:
	void fun(){ // //子类内部访问基类成员时,编译器需要查看这些成员在 基类中的原始标记
		m_a = 100;
		Base::foo();// 子类的foo函数将基类的foo函数隐藏,但可以通过作用域限定符访问基类的foo
		m_b = 100;
		bar();  //子类内部可以直接访问 基类的 非私有(共有/保护)成员(变量/函数)
	}
private:
	int m_d;
};
// protected继承的独特点
class protectedBase :protected Base{// 子类将对基类的成员重新标记访问限定符
	// 子类将对基类的成员重新标记访控限定 m_a/foo是protected m_b/bar是protected m_c/hum是private
public:
	void fun(){ //子类内部访问基类成员时,编译器需要查看这些成员在 基类中的原始标记
		m_a = 100;
		Base::foo();// 子类的foo函数将基类的foo函数隐藏,但可以通过作用域限定符访问基类的foo
		m_b = 100;
		bar();  //子类内部可以直接访问 基类的 非私有(共有/保护)成员(变量/函数)
	}
private:
	int m_d;
};
// private继承的独特点
class privateBase :private Base{// 子类将对基类的成员重新标记访问限定符
	// 子类将对基类的成员重新标记访控限定 m_a/foo是private m_b/bar是private m_c/hum是private
public:
	void fun(){ //子类内部访问基类成员时,编译器需要查看这些成员在 基类中的原始标记
		m_a = 100;
		Base::foo();// 子类的foo函数将基类的foo函数隐藏,但可以通过作用域限定符访问基类的foo
		m_b = 100;
		bar();  //子类内部可以直接访问 基类的 非私有(共有/保护)成员(变量/函数)
	}
private:
	int m_d;
};
int main(){
	publicBase d;// 利用子类对象在类外访问 基类成员时,编译器需要查看这些成员在 子类中的重新标记
	d.m_a = 10;
	d.foo();
	//d.m_b = 10; // err
	//d.bar();// err
	//d.m_c = 30;// err
	//d.hum();// err
	protectedBase b;// 利用子类对象在类外访问 基类成员时,编译器需要查看这些成员在 子类中的重新标记
	//b.m_a = 10;// err
	//b.foo();// err
	//b.m_b = 10; // err
	//b.bar();// err
	//b.m_c = 30;// err
	//b.hum();// err
	privateBase cd;// 利用子类对象在类外访问 基类成员时,编译器需要查看这些成员在 子类中的重新标记
	//cd.m_a = 10;// err
	//cd.foo();// err
	//cd.m_b = 10; // err
	//cd.bar();// err
	//cd.m_c = 30;// err
	//cd.hum();// err
	return 0;
}
基类中的在公有子类中标记为在保护子类中标记为在私有子类中标记为
公有成员公有成员保护成员私有成员
保护成员保护成员保护成员私有成员
私有成员私有成员私有成员私有成员
  • “通过”子类访问其所继承的基类的成员时,需要考虑因继承方式对访问控制限定的影响

2.3 公有继承的独有特点

(1) 只有在公有继承下,子类对象在类外可以访问基类的 公有成员(其他继承不可以)
(2) 如果被子类同名标识符隐藏可以借助::指明访问基类的成员
(3) 只有在公有继承下 子类类型指针 和 基类类型指针 之间可以进行转换
子类类型引用 和 基类类型引用 之间可以进行转换

class publicBase :public Base{
public:
	void foo(){
		cout << "publicBase::foo" << endl;
	}
private:
	int m_d;
};
class Human{
public:
	int m_d;
	string m_name;
};
class Student :public Human{
public :
	int m_no;
};
int main(){
	publicBase b;
	b.m_a = 1000;
	b.foo(); // 调用的是自己的
	b.Base::foo(); // 调用的是基类的
	Human h;
	cout << "基类对象h的大小" << sizeof(h) << endl;
	Student s;
	cout << "子类对象s的大小" << sizeof(s) << endl;
	// 子类类型指针 和 基类类型指针
	Human* ph = &s; // Student* --> Human*
	// 子类类型引用 和 基类类型引用
	Human& rh = s;
	// 以上两种转换,编译器认为访问范围缩小,是安全的
	//Student* ps = &h;
	//Student& rs = h;
	// 以上两种转换,编译器认为访问范围扩大,是危险的
	Student* ps = static_cast<Student*> (&h);
	Student& rs = static_cast<Student&>(h);
	// 通过静态转换虽然可以成功,但是风险依旧存在,极其不建议这么使用
	Student* ps = static_cast<Student*>(ph);// ph 指向的就是C6_Student的对象
	Student& rs = static_cast<Student&>(rh);// rh 就是C6_Student对象的引用
	// 以上两种转换毫无风险,极其建议大家这么做
	// 基类指针或引用的实际目标,究竟是不是子类对象,完全由我们自己判断
	return 0;
}

向上造型:

  • 子类类型指针 隐式 转换为基类类型指针
  • 子类类型引用 隐式 转换为基类类型引用

3、子类的构造、析构

3.1 子类的构造

  • 子类没有定义构造函数
    • 编译器为子类提供的默认无参构造函数,定义基类子对象,并调用其基类的无参构造函数,构造该子类对象中的基类子对象。
  • 子类定义构造函数但没有在初始化表中指明基类部分构造方式
    • 定义基类子对象,并调用其基类的无参构造函数,构造该子类对象中的基类子对象。
  • 子类定义构造函数并在初始化表中指明基类部分构造方式
    • 定义基类子对象并 调用指明的其基类的构造函数。
  • 子类对象的构造过程
    • 构造基类子对象->构造成员变量->执行构造代码

3.2 子类的析构

  • 子类没有定义析构函数
    • 编译器将提供一个默认析构函数,析构完所有的成员变量以后,会自动调用其基类的析构函数.
  • 子类定义析构函数
    • 子类的析构函数在执行完自身析构代码,并析构完所有的成员变量以后,会自动调用其基类的析构函数.
  • 子类对象的析构过程
    • 执行析构代码->析构成员变量->析构基类子对象

3.3 子类的拷贝构造函数

  • 子类没有定义拷贝构造函数
    • 编译器为子类提供的默认拷贝构造函数,定义基类子对象,并调用其基类的拷贝构造函数构造该子类对象中的基类子对象
  • 子类定义了拷贝构造函数,但没有在初始化表指明其基类部分的构造方式
    • 定义基类子对象,并调用其基类的无参构造函数,构造该子类对象中的基类子对象
  • 子类定义了拷贝构造函数,同时初始化表中指明了其基类部分以拷贝方式构造
    • 定义基类子类对象,并调用其基类的拷贝构造函数,构造该子类对象中的基类子对象

3.4 子类的拷贝赋值

  • 子类没有定义拷贝赋值函数
    • 编译器为子类提供的缺省拷贝赋值函数,会自动调用其基类的拷贝赋值函数,复制该子类对象中的基类子对象
  • 子类定义了拷贝赋值函数,但没有显式调用其基类的拷贝赋值函数
    • 子类对象中的基类子对象将得不到复制
  • 子类定义了拷贝赋值函数,同时显式调用了其基类的拷贝赋值函数
    • 子类对象中的基类子对象将得到复制
class C6_people{
public:
	C6_people(int age = 0, const char*name = "无名"):m_age(age), m_name(name){
		//【int m age=age;】定义mage,初值为age
		//【string m name(name);】定义m name,利用m name,string(name)
		cout << "people类的缺省构造函数被调用" << endl;
	}
	C6_people(const C6_people&that):m_age(that.m_age),m_name(that.m_name){
		// 【int m_age = that, mage; 】定义mage, 初值为that.m age
		//【string m name=that.m name;】定义m name,利用m name.string(that.m name)
		cout << "people类的拷贝构造函数被调用" << endl;
	}
	C6_people&operator=(const C6_people& that){
		//编译器不会在自定义拷贝赋值函数中塞任何操作
		cout << "people类的拷贝赋值函数被调用" << endl;
		this->m_age=that.m_age;
		this->m_name=that.m_name; // this->m name.operator=(that.m name)
		return *this;
	}
	~C6_people(){
		cout << "C6_people类的析构函数被调用" << endl;
		//对于基本类型的成员变量m_age,什么都不做
		//对于类类型的成员变量m_name,利用m_name,~string()
		//释放m_age/m_name本身所占内存空间
	}
	void getinfo(){
		cout << "姓名:" << m_name << ",年龄:" << m_age ;
	}
private:
	int m_age;// 基本类型成员变量
	string m_name;// 类类型成员变量
};
class C6_stu : public C6_people{
public:
	//子类没有定义构造函数编译器为子类提供的默认无参构造函数
	//C6_stu(){
	//	【Human(); 】定义基类子对象,利用基类子对象.Human()
	//  【float m score; 】
	//	【string m remark; 】
	//}
	C6_stu(int age = 45, string name = "张三", float score = 0.0, string remark = "优秀") :m_score(score), m_remark(remark), C6_people(age,name.c_str()){
		cout << "基类的缺省构造被调用了" << endl;
	}
	void getinfo(){
		C6_people::getinfo();
		cout << "分数:" << m_score << "评语:" << m_remark << endl;
	}
	//子类没有定义析构函数编译器将提供一个默认析构函数
	//~C6_stu(){
	//对于基本类型的成员变量m_score,什么都不做
	//对于类类型的成员变量m m_remark,利用m_remark,~string()
	// 对于基类子对象,利用基类子对象.~C6_people()
	//释放m_score/m_remark本身所占内存空间
	//}
	~C6_stu(){
		cout << "C6_stu类的析构函数被调用" << endl;
	}
	//子类没有定义拷贝构造函数编译器为子类提供的默认拷贝构造函数
	//C6_stu(const C6_stu& that){
	//	// [C6_people(that)] 定义基类子对象,利用基类子对象.C6_people(that) ->C6_people类拷贝构造函数
	//	// ...
	//}
	// 子类没有定义拷贝赋值函数编译器为子类提供的缺省拷贝赋值函数
	//C6_stu& operator=(const C6_stu& that){
	//	C6_people *p = this;
	//	*p = that;// C6_people类的拷贝赋值函数
	//}

private:
	float m_score;
	string m_remark;
};
int main(){
	cout << "----s1" << endl;
	C6_stu s1(22,"李四",89.7,"良好");// 构造
	s1.getinfo();
	cout << "----s2" << endl;
	C6_stu s2 = s1; // 拷贝构造
	s2.getinfo();
	cout << "----s3" << endl;
	C6_stu s3;
	cout << "s3赋值前" << endl;
	s3.getinfo();
	s3 = s2; // 赋值拷贝
	cout << "s3赋值后" << endl;
	s3.getinfo();
	return 0;
}

4、多重继承

4.1 内存布局

  • 子类对象中的多个基类子对象,按照继承表的顺序依次被构造,析构的顺序则与构造严格相反,各个基类子对象按照从低地址到高地址排列
    在这里插入图片描述
class C06_A{
public:
	int m_a;
	C06_A(){ cout << "C06_A构造" << endl; }
	~C06_A(){ cout << "C06_A析构" << endl; }
};
class C06_B{
public:
	int m_b;
	C06_B(){ cout << "C06_B构造" << endl; }
	~C06_B(){ cout << "C06_B析构" << endl; }
};
class C06_C{
public:
	int m_c;
	C06_C(){ cout << "C06_C构造" << endl; }
	~C06_C(){ cout << "C06_C析构" << endl; }
};
class C06_D :public C06_A, public C06_B, public C06_C{ // 汇聚子类
public:
	int m_d;
	C06_D(){ cout << "C06_D构造" << endl; }
	~C06_D(){ cout << "C06_D析构" << endl; }
};
int main(){
	C06_D d;
	cout << "汇聚子类对象d的大小:" << sizeof(d) << endl;
	C06_D * pd = &d;
	cout << "整个汇聚子类对象的首地址D* pd:" << pd << endl;
	cout<< "A基类子对象的首地址:" << &d.m_a<<endl;
	cout << "B基类子对象的首地址:" << &d.m_b << endl;
	cout << "C基类子对象的首地址:"<<&d.m_c<< endl;
	cout << "D基类子对象的首地址:" << &d.m_d << endl;
	return 0;
}

4.2 类型转换

  • 将多重继承的子类对象的指针,隐式转换为它的基类类型,编译器会根据各个基类子对象在子类对象中的内存位置,进行适当的偏移计算
  • 反之,将任何一个基类类型的指针静态转换为子类类型,编译器同样会进行适当的偏移计算
  • 无论在哪个方向上,重解释类型转换(reinterpret_cast)都不进行任何偏移计算–不要使用
    在这里插入图片描述
int main(){
	C06_D d;
	cout << "汇聚子类对象d的大小:" << sizeof(d) << endl;
	C06_D * pd = &d;
	cout << "整个汇聚子类对象的首地址D* pd:" << pd << endl;// 004FF730
	cout << "A基类子对象的首地址:" << &d.m_a << endl; // 004FF730
	cout << "B基类子对象的首地址:" << &d.m_b << endl; // 004FF734
	cout << "C基类子对象的首地址:" << &d.m_c << endl; // 004FF738
	cout << "D基类子对象的首地址:" << &d.m_d << endl; // 004FF73C
	C06_A* pa = pd;
	cout << "隐式转换" << endl;
	cout << "D* pd ---> A* pa:" << pa << endl; // 004FF730
	C06_B* pb = pd;
	cout << "D* pb ---> B* pb:" << pb << endl; // 004FF734
	C06_C* pc = pd;
	cout << "D* pd ---> C* pc:" << pc << endl; // 004FF738
	cout << "静态转换" << endl;
	C06_D* p1 = static_cast<C06_D*>(pa);
	cout << "A* pd ---> D* p1:" << p1 << endl; // 004FF730
	C06_D* p2 = static_cast<C06_D*>(pb);
	cout << "B* pb ---> D* p2:" << p2 << endl; // 004FF730
	C06_D* p3 = static_cast<C06_D*>(pc);
	cout << "C* pc ---> D* p3:" << p3 << endl; // 004FF730
	return 0;
}
  • 引用的情况与指针类似,因为引用的本质就是指针
    在这里插入图片描述

4.3 名字冲突问题

  • 如果在子类的多个基类中,存在同名的标识符,那么任何试图通过子类对象,或在子类内部访问该名字的操作,都将引发歧义。
    名字冲突问题解决方法
  • 子类隐藏该标识符–不建议使用
  • 通过作用域限定操作符“::”显式指明所属基类
class C06_E{
public:
	int m_a;
	int m_c;
};
class C06_F{
public:
	int m_b;
	int m_c;
};
class C06_G :public C06_E, public C06_F{
public:
	int m_d;
	void foo(){
		// m_c = 100;歧义
		C06_E::m_c = 100;
	}
};
int main(){
	C06_G g;
	cout << "汇聚子类对象g的大小:" << sizeof(g) << endl;
	// g.m_c=100; 歧义
	g.C06_E::m_c = 100;
	return 0;
}

5、砖石继承

  • 砖石继承的问题
    一个子类继承自多个基类,而这些基类又源自共同的祖先,这样的继承结构称为钻石继承(菱形继承)
    在这里插入图片描述
class C06_AA{ // 公共基类
public:
	int m_a;
};
class C06_X :public C06_AA{ // 中间子类
public:
	int m_x;
};
class C06_Y :public C06_AA{ // 中间子类
public:
	int m_y;
};
class C06_Z :public C06_X, public C06_Y{ // 汇聚子类
public:
	int m_z;
};
int main(){
	C06_Z z; // X中间子类子对象|Y中间子类子对象|m_z|-->
			// A公共基类子对象 m_x|A公共基类子对象 m_y|m_z|-->
			// m_a m_x |m_a m_y|m_z|
	cout << "汇聚子类对象g的大小:" << sizeof(z) << endl;// 20
	return 0;
}
  • 钻石继承问题
    在汇聚子类内部,或通过汇聚子类对象,访问公共基类的成员,会因继承路径的不同而导致匹配歧义

6、虚继承

解决砖石继承存在的问题而诞生的

  • 在继承表中使用virtual关键字

  • 虚继承可以保证
    (1)公共虚基类子对象在汇聚子类对象中仅存一份实例
    在这里插入图片描述

    (2)公共虚基类子对象被多个中间子类子对象所共享
    虚继承实现原理

  • 汇聚子类对象中的每个中间子类子对象都持有一个指针,通过该指针可以获取中间子类子对象的首地址公共虚基类子对象的首地址的偏移量
    在这里插入图片描述

class C06_AA{ // 公共基类
public:
	int m_a;
};
class C06_X :virtual public C06_AA{ // 中间子类
public:
	int m_x;
	void setAge(/* X* this */int age){
		m_a = age; // this -> X 中间子类子对象-》指针1-》偏移量-》this+偏移量-》A公共基类子对象-》m_a
	}
	
};
class C06_Y :virtual public C06_AA{ // 中间子类
public:
	int m_y;
	int getAge(/* Y* this*/){ 
		return m_a;// this->Y 中间子类子对象 - 》指针2 - 》偏移量 - 》this + 偏移量 - 》A公共基类子对象 - 》m_a
	}
};
class C06_Z :public C06_X, public C06_Y{ // 汇聚子类
public:
	int m_z;
};
int main(){
	C06_Z z; // X中间子类子对象|Y中间子类子对象|m_z|A公共基类子对象|-->
			// 指针1 m_x |指针2 m_y|m_z|m_a|
	cout << "汇聚子类对象g的大小:" << sizeof(z) << endl;// 32
	z.setAge(100); // setAge(&z) -->实参类型Z*
	cout << "age:" << z.getAge() << endl; // getAge(&z) -->实参类型Z*
	return 0;
}

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

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

相关文章

C语言 | Leetcode C语言题解之第117题填充每个节点的下一个右侧节点指针II

题目&#xff1a; 题解&#xff1a; void handle(struct Node **last, struct Node **p, struct Node **nextStart) {if (*last) {(*last)->next *p;}if (!(*nextStart)) {*nextStart *p;}*last *p; }struct Node *connect(struct Node *root) {if (!root) {return NULL…

【小呆的力学笔记】连续介质力学的知识点回顾一:运动和变形

文章目录 1. 运动的描述2. 拉格朗日描述下的变形2.1 线元的变化2.2 体元的变化2.3 面元的变化 1. 运动的描述 在连续介质力学中&#xff0c;存在着两种对运动的描述&#xff0c;一种为拉格朗日描述&#xff0c;即通过描述每个物质点的运动来描述整个变形体的运动&#xff0c;也…

解决IDEA菜单栏找不到VCS的问题,且使用IDEA推送新项目到托管仓库

问题描述&#xff1a; 在idea软件中使用git推送项目&#xff0c;idea页面顶部菜单栏无VCS 解决方案&#xff1a; 一&#xff1a;File->Settings->Version Control-> 点击 ->选择项目->VCS:->点击ok&#xff1a; 二&#xff1a;托管平台创建一个Git仓库来保…

基于遗传优化的货柜货物摆放优化问题求解matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于遗传优化的货柜货物摆放优化问题求解matlab仿真。在一个货架上&#xff0c;初始状态下&#xff0c;随机将货物放在货柜上&#xff0c;优化之后&#xff0c;整…

openresty(Nginx) 隐藏 软包名称及版本号 升级版本

1 访问错误或者异常的URL 2 修改配置&#xff0c;重新编译&#xff0c;升级 #修改版本等 vim ./bundle/nginx-1.13.6/src/core/nginx.h #define nginx_version 1013006 #define NGINX_VERSION "1.13.6" #define NGINX_VER "openresty/&q…

玩转STM32-直接存储器DMA(详细-慢工出细活)

文章目录 一、DMA介绍1.1 DMA简介1.2 DMA结构 二、DMA相关寄存器&#xff08;了解&#xff09;三、DMA的工作过程&#xff08;掌握&#xff09;四、DMA应用实例4.1 DMA常用库函数4.2 实例程序 一、DMA介绍 1.1 DMA简介 DMA用来提供外设与外设之间、外设与存储器之间、存储器与…

中国企业出海,哪些业务需要负载均衡?

国内企业出海的进程正在加速。中国的出海企业剑指跨境电商、社交、游戏、短剧等市场&#xff0c;其中尤其以跨境电商的数据最为突出。据官方数据&#xff0c;2023年我国跨境电商进出口总额达到2.38万亿元&#xff0c;比2016年增长近50倍&#xff0c;占货物贸易总规模的5.7%。 …

【Mybatis】映射文件中获取单个参数和多个参数的写法

xml的映射文件中获取接口方法中传来的参数是直接用#{}的方式来获取的 那么接下来&#xff0c;我们就具体来说一下获取参数里边的各种规则和用法 1.单个参数&#xff0c;比如上面的getOneUser&#xff0c;只有一个id值作为参数 Mybatis对于只有一个参数的情况下&#xff0c;不…

机器学习-5-如何进行交叉验证

参考一文带您了解交叉验证(Cross-Validation):数据科学家必须掌握的7种交叉验证技术 参考如何在机器学习中使用交叉验证(实例) 1 交叉验证 1.1 交叉验证的本质 针对中小型数据集常用的一种用于观察模型稳定性的方法——交叉验证。 交叉验证是用来观察模型的稳定性的一种方…

计算机毕业设计hadoop+spark+hive物流大数据分析平台 物流预测系统 物流信息爬虫 物流大数据 机器学习 深度学习

流程&#xff1a; 1.Python爬虫采集物流数据等存入mysql和.csv文件&#xff1b; 2.使用pandasnumpy或者MapReduce对上面的数据集进行数据清洗生成最终上传到hdfs&#xff1b; 3.使用hive数据仓库完成建库建表导入.csv数据集&#xff1b; 4.使用hive之hive_sql进行离线计算&…

基于NAMUR开放式架构(NOA)的工业设备数据采集方案

一 NAMUR开放式架构 传统自动化金字塔结构的优越性在过去许多年里已被证明。然而&#xff0c;传统的自动化金字塔在获取和利用对物联网和工业4.0有价值的数据方面却存在一定挑战。这是因为传统系统通常是封闭的&#xff0c;数据访问受到限制&#xff0c;难以集成到新的数字化解…

eclipse启动时间过长的问题

项目场景&#xff1a; 由于我用eclipse比较习惯&#xff0c;虽然IDEA很好&#xff0c;但是因为收费&#xff0c;所以在个人开发学习过程中一直还是使用eclipse&#xff0c;本文不讨论eclipse与IDEA孰优孰劣问题。 开发环境&#xff1a; 操作系统&#xff1a;Windows 11 22631…

HCIP-Datacom-ARST自选题库__BGP/MPLS IP VPN简答【3道题】

1.在BGP/MPLSIPVPN场景中&#xff0c;如果PE设备收到到达同一目的网络的多条路由时&#xff0c;将按照定的顺序选择最优路由。请将以下内容按照比较顺序进行排序。 2.在如图所示的BGP/MPLSIP VPN网络中&#xff0c;管理员准备通过Hub-Spoke组网实现H站点对VPM流量的集中管控&am…

数字化校园的特征

"数字化校园"是校园信息化进入高级阶段的表现形式&#xff0c;信息技术与教育教育的交融应该更深化。因而&#xff0c;数字化校园应该具以下特征&#xff1a; 1.互联网络高速发展 网络是信息时代的根基&#xff0c;没有网络就无法完成教育信息化的绝大部分作业。数字…

启智CV机器人,ROS

资料&#xff1a; https://wiki.ros.org/kinetic/Installation/Ubuntu https://blog.csdn.net/qq_44339029/article/details/120579608 装VM。 装ubuntu20.04 desktop.iso系统。 装vm工具&#xff1a; sudo apt update sudo dpkg --configure -a sudo apt-get autoremove o…

MagicPose4D:解锁AI驱动的3D模型动作新纪元

在当今快速发展的数字内容创作领域,MagicPose4D正以其革命性的技术颠覆传统动画制作流程,成为创作者手中的魔法棒。这款先进的框架不仅仅是一款工具,更是通往无限创意的一扇门,它使得为3D模型赋予生动、自然的动作变得前所未有的简单和高效。下面,让我们深入探索MagicPose…

技术创新加速生态繁荣 | 软通动力子公司鸿湖万联亮相OpenHarmony开发者大会2024

5月25日&#xff0c;由开放原子开源基金会OpenHarmony项目群工作委员会主办的OpenHarmony开发者大会2024在深圳成功举行。本次大会紧扣OpenHarmony 4.1 Release版本发布契机&#xff0c;以“鸿心聚力&#xff0c;智引未来”为主题、通过“1场主论坛6场技术分论坛”承载&#xf…

MongoDB数据库(10亿条数据)清理策略: 自动化过期数据删除实战

1、引言 随着应用程序和业务数据的持续增长&#xff0c;有效地管理数据库存储空间成为维护系统性能的关键。在MongoDB这类NoSQL数据库中&#xff0c;定期清理过期数据变得尤为重要&#xff0c;这不仅能释放宝贵的存储资源&#xff0c;还能优化查询性能&#xff0c;确保数据库运…

一种基于单片机的智能饮水机设计

随着人们生活水平的提高&#xff0c;对美好生活质量的追求也越来越高。饮 水机是人们日常生活不可或缺的&#xff0c;实现饮水机的智能化控制不但方便&#xff0c; 而且更加安全。本文提出一种基于单片机的智能饮水控制系统&#xff0c;通过传 感器实现对水温的监测&#xff0c…

【DrissionPage爬虫库 1】两种模式分别爬取Gitee开源项目

文章目录 DrissionPage爬虫库简介1. 浏览器操控模式&#xff08;类似于游戏中的后台模拟鼠标键盘&#xff09;2. 数据包收发模式&#xff08;类似于游戏中的协议封包&#xff09; 实战中学习需求&#xff1a;爬取Gitee开源项目的标题与描述解决方案1&#xff1a;用数据包方式获…