类和对象03

六、继承

我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。

这个时候我们就可以考虑利用继承的技术,减少重复代码

6.1 继承的基础语法

例如我们看到很多网站中, 都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同接下来我们分别利用普通写法和继承的写法来实现网页中的内容,看一下继承存在的意义以及好处

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//继承实现页面
//继承的好处:减少重复代码
//语法: class 子类 : 继承方式 父类
//子类  也称为  派生类
//父类  也称为  基类class BasePage {
public:void header() {cout << "首页、公开课、登录、注册...(公共头部)" << endl;}void footer() {cout << "帮助中心、交流合作、站内地图...()" << endl;}void left() {cout << "Java、Python、C++...(公共分类列表)" << endl;}
};//Java页面
class Java : public BasePage {
public:void content() {cout << "Java学科视频" << endl;}
};//Python页面
class Python : public BasePage {
public:void content() {cout << "Python学科视频" << endl;}
};//C++页面
class CPP : public BasePage {
public:void content() {cout << "CPP学科视频" << endl;}
};void test01() {cout << "Java下载视频页面如下:" << endl;Java ja;ja.header();ja.footer();ja.left();ja.content();cout << "---------------" << endl;cout << "Python下载视频页面如下:" << endl;Python py;py.header();py.footer();py.left();py.content();cout << "---------------" << endl;cout << "C++下载视频页面如下:" << endl;CPP cpp;cpp.header();cpp.footer();cpp.left();cpp.content();}int main() {test01();system("pause");return 0;}

总结:

继承的好处:可以减少重复的代码  class A : public B;

A类称为子类或派生类 。B类称为父类或基类

派生类中的成员,包含两大部分:

一类是从基类继承过来的,一类是自己增加的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。

6.2 继承方式

继承的语法:

class 子类 : 继承方式 父类

 继承方式一共有三种:

公共继承   保护继承   私有继承

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//公共继承
class Base1 {
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son1 : public Base1 {
public:void func() {m_A = 10;//父类中的公共权限成员,到子类中依然是公共权限m_B = 10;//父类中的保护权限成员,到子类中依然是保护权限//m_C = 10;父类中私有访问权限 子类访问不到}
};void test01() {Son1 s1;s1.m_A = 100;//s1.m_B = 100;//报错,到Son1中m_B为保护权限类外无法访问}//保护继承
class Base2 {
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son2 : private Base2 {
public:void func() {m_A = 10;//父类中的公共权限成员,到子类中变为了保护权限m_B = 10;//父类中的保护权限成员,到子类中依然是保护权限//m_C = 10;父类中私有访问权限 子类访问不到}
};void test02() {Son2 s2;//s2.m_A = 100; //在Son2中m_A变为保护权限,因此类外访问不到//s2.m_B = 100; //在Son2中mB保护权限不可以访问}//私有继承
class Base3 {
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son3 : private Base3 {
public:void func() {m_A = 10;//父类中的公共权限成员,到子类中变为了私有权限m_B = 10;//父类中的保护权限成员,到子类中变为了私有权限//m_C = 10;父类中私有访问权限 子类访问不到}
};void test03() {Son3 s3;//s3.m_A = 100; //在Son3中m_A变为私有权限,因此类外访问不到//s3.m_B = 100; //在Son2中m_B私有权限不可以访问}
//
//class GrandSon3 : private Son3 {
//public:
//	void func() {
//		m_A = 100;//变为私有无法访问
//	}
//};int main() {test01();test02();test03();system("pause");return 0;}

6.3 继承中的对象类型

问题:从父类继承过来的成员,哪些属于子类对象中?

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//继承中的对象模型
class Base {
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son : public Base {
public:int m_D;
};void test01() {//16	//父类中所有非静态成员属性都会被子类继承下去//父类中私有成员属性是被编译器给隐藏了,因此是访问不到,但是确实被继承下去了cout << "size of son = " << sizeof(Son) << endl;
}int main() {test01();system("pause");return 0;}

利用Developer Command Prompt for vs 2022查看对象模型

跳转到盘符  D:

跳转文件路径cd具体路径下

查看命名
cl /d1 reportSingleClassLayout类名 文件名

6.4 继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数

问题:父类和子类的构造和析构顺序是谁先谁后?

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//继承中构造和析构的顺序
class Base {
public:Base() {cout << "Base的构造函数" << endl;}~Base() {cout << "Base的析构函数" << endl;}
};class Son : public Base {
public:Son() {cout << "Son的构造函数" << endl;}~Son() {cout << "Son的析构函数" << endl;}
};void test01() {//继承中的构造和析构顺序如下://先构造父类,再构造子类,析构的顺序与构造的顺序相反Son s;
}int main() {test01();system("pause");return 0;}

总结:继承中先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

6.5 继承同名成员的处理方式

问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?

·访问子类同名成员,直接访问即可

 ·访问父类同名成员,需要加作用域

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Base {
public:Base() {m_A = 100;}void func() {cout << "Base - func() 调用" << endl;}void func(int a) {cout << "Base - func(int a) 调用" << endl;}int m_A;
};class Son : public Base {
public:Son() {m_A = 200;}void func() {cout << "Son - func() 调用" << endl;}int m_A;
};
//同名成员属性处理
void test01() {Son s;cout << "Son 下的 m_A = " << s.m_A << endl;//如果通过子类对象―访问到父类中同名成员,需要加作用域cout << "Base 下的 m_A = " << s.Base::m_A << endl;
}
//同名成员函数处理
void test02() {Son s;s.func();//直接调用调用是子类中的同名成员s.Base::func();//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数//所以加作用域s.Base::func(100);}int main() {test01();test02();system("pause");return 0;}

 总结:

1.子类对象可以直接访问到子类中同名成员

2.子类对象加作用域可以访问到父类同名成员

3.当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

6.6 继承同名静态成员处理方式

问题:继承中同名的静态成员在子类对象上如何进行访问?

静态成员和非静态成员出现同名,处理方式一致

1.访问子类同名成员直接访问即可

2.访问父类同名成员需要加作用域

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Base {
public:static int m_A;static void func() {cout << "Base - static void func()" << endl;}
};int Base::m_A = 100;class Son : public Base {
public:static int m_A;static void func() {cout << "Son - static void func()" << endl;}
};
int Son::m_A = 200;//同名静态成员属性
void test01() {Son s;//1.通过对象访问cout << "通过对象访问" << endl;cout << "Son 下的 m_A =  " << s.m_A << endl;cout << "Base 下的 m_A =  " << s.Base::m_A << endl;//2.通过类名访问cout << "通过类名访问" << endl;cout << "Son 下的 m_A =  " << Son::m_A << endl;//第一个::代表通过类名方式访问// 第二个::代表访问父类作用域下cout << "Base 下的 m_A =  " << Son::Base::m_A << endl;
}//同名静态函数
void test02() {Son s;//1.通过对象访问cout << "通过对象访问" << endl;s.func();s.Base::func();//2.通过类名访问cout << "通过类名访问" << endl;Son::func();Son::Base::func();}int main() {test01();test02();system("pause");return 0;}

总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象和通过类名)

6.7 多继承语法

C++允许一个类继承多个类

语法:

class 子类∶继承方式 父类1,继承方式 父类2...

多继承可能会引发父类中有同名成员出现,需要加作用域区分

C++实际开发中不建议用多继承

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Base1 {
public:Base1() {m_A = 100;}int m_A;
};class Base2 {
public:Base2() {m_A = 200;}int m_A;
};//子类需要继承Base1和Base2
class Son : public Base1 ,public Base2{
public:Son() {m_C = 300;m_D = 400;}int m_C;int m_D;
};void test01() {Son s;//16个cout << "sizeof Son = " << sizeof(Son) << endl;//当父类中出现同名成员,需要加作用域区分cout << "Base1 下的 m_A = " << s.Base1::m_A << endl;cout << "Base2 下的 m_A = " << s.Base2::m_A << endl;
}int main() {test01();system("pause");return 0;}

总结:多继承中如果父类中出现了同名情况,子类使用时候要加作用域

6.8 菱形继承

菱形继承概念:

两个派生类继承同一个基类    又有某个类同时继承者两个派生类   这种继承被称为菱形继承,或者钻石继承

eg.

菱形继承问题:

1.羊继承了动物的数据,范同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。

⒉草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Animal {
public:int m_Age;
};//利用虚继承解决菱形继承的问题
//继承之前加上关键字virtual变为虚继承
//Animal类称为虚基类
//羊类
class Sheep : virtual public Animal{};//驼类
class Tuo : virtual public Animal{};//羊驼类
class SheepTuo : public Sheep,public Tuo{};void test01() {SheepTuo st;st.Sheep::m_Age = 18;st.Tuo::m_Age = 28;//当菱形继承,两个父类拥有相同数据,需要加以作用域区分cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;cout << "st.m_Age = " << st.m_Age << endl;//这份数据我们知道只有有一份就可以,菱形继承导致数据有两份,资源浪费}int main() {test01();system("pause");return 0;}

 总结:

1.菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义

2.利用虚继承可以解决菱形继承问题

七、多态

7.1 多态的基本概念

多态是C++面向对象三大特性之一多态分为两类

1.静态多态:函数重载和这算符重载属于静态多态,复用函数名

2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态区别:

·静态多态的函数地址早绑定–编译阶段确定函数地址

·动态多态的函数地址晚绑定–运行阶段确定函数地址

下面通过案例进行讲解多态

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Animal {
public://虚函数实现地址晚绑定virtual void speak() {cout << "动物在说话" << endl;}
};class Cat :  public Animal {
public://重写函数返回值类型函数名参数列表完全相同virtual这里写不写都行virtual void speak() {cout << "小猫在说话" << endl;}
};class Dog : public Animal {
public:void speak() {cout << "小狗在说话" << endl;}
};//执行说话的函数
//地址早绑定在编译阶段确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定//动态多态满足条件
//1、有继承关系
//2、子类重写父类的虚函数//动态多态使用
//父类的指针或者引用 指向子类对象void doSpeak(Animal& animal) { //Animal &animal = cat;animal.speak();
}void test01() {Cat cat;Dog dog;doSpeak(cat);doSpeak(dog);
}int main() {test01();system("pause");return 0;}

总结:

多态满足条件:

1.有继承关系

2.子类重写父类中的虚函数

多态使用条件:父类指针或引用指向子类对象

重写:函数返回值类型函数名参数列表完全—致称为重写

原理剖析:

7.2 多态案例一-计算器类

案例描述:

分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类

多态的优点:

1.代码组织结构清晰

2.可读性强

3.利于前期和后期的扩展以及维护

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//普通写法
class Calculator {
public:int getResult(string oper) {if (oper == "+") {return m_Num1 + m_Num2;}else if (oper == "-") {return m_Num1 - m_Num2;}else if (oper == "*") {return m_Num1 * m_Num2;}}int m_Num1;int m_Num2;
};void test01() {Calculator c;c.m_Num1 = 10;c.m_Num2 = 10;cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;//如果想扩展新的功能,需求修改源码//在真实开发中提倡开闭原则//开闭原则:对扩展进行开发,对修改进行关闭
}//利用多态实现计算器
//多态好处:
//1、组织结构清晰
//2、可读性强
//3、对于前期和后期扩展以及维护性高
class AbstractCaluator {
public:virtual int getResult() {return 0;}int m_Num1;int m_Num2;
};//加法计算器类
class AddCalculator : public AbstractCaluator {int getResult() {return m_Num1 + m_Num2;}
};
//减法计算器类
class SubCalculator : public AbstractCaluator {int getResult() {return m_Num1 - m_Num2;}
};
//乘法计算器类
class MulCalculator : public AbstractCaluator {int getResult() {return m_Num1 * m_Num2;}
};void test02() {//多态使用条件//父类指针或者引用指向子类对象//加法运算AbstractCaluator* abc = new AddCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;//用完后记得销毁delete abc;//减法运算abc = new SubCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;delete abc;//乘法运算abc = new MulCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;delete abc;
}int main() {//test01();test02();system("pause");return 0;}

总结:C++开发提倡利用多态设计程序架构,因为多态优点很多

7.3 纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容

因此可以将虚函数改为纯虚函数

纯虚函数语法:

virtual 返回值类型 函数名 (参数列表) =  0 ;

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

1.无法实例化对象

2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Base {
public://纯虚函数//只要有一个纯虚函数,这个类称为抽象类//抽象类特点://1、无法实例化对象//2、抽象类的子类必须要重写父类中的纯虚函数,否则也属于抽象类virtual void func() = 0;
};class Son : public Base {
public:virtual void func() {cout << "func函数调用" << endl;}
};void test01() {/*Base b;无法实例化对象new Base;*///Son s;//子类必须重写父类中的纯虚函数,否则无法实例化对象Base* base = new Son;base->func();}int main() {test01();system("pause");return 0;}

7.4 多态案例二-制作饮品

案例描述:

制作饮品的大致流程为:煮水-冲泡–倒入杯中–加入辅料

利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class AbstractDrinking {
public://煮水virtual void Boil() = 0;//冲泡virtual void Brew() = 0;//倒入杯中virtual void PourInCup() = 0;//加入辅料virtual void PutSomeThing() = 0;//制作饮品void makeDrink() {Boil();Brew();PourInCup();PutSomeThing();}
};//制作咖啡
class Coffee : public AbstractDrinking {
public://煮水virtual void Boil() {cout << "煮农夫山泉" << endl;}//冲泡virtual void Brew() {cout << "冲泡咖啡" << endl;}//倒入杯中virtual void PourInCup() {cout << "倒入杯中" << endl;}//加入辅料virtual void PutSomeThing() {cout << "加入糖和牛奶" << endl;}
};//制作茶叶
class Tea : public AbstractDrinking {
public://煮水virtual void Boil() {cout << "煮矿泉水" << endl;}//冲泡virtual void Brew() {cout << "冲泡茶叶" << endl;}//倒入杯中virtual void PourInCup() {cout << "倒入杯中" << endl;}//加入辅料virtual void PutSomeThing() {cout << "加入枸杞" << endl;}
};void doWork(AbstractDrinking* abs) {abs->makeDrink();delete abs;//释放
}void test01() {//制作咖啡doWork(new Coffee);cout << "-----------" << endl;//制作茶叶doWork(new Tea);}int main() {test01();system("pause");return 0;}

7.5 虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

 解决方式:将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

1.可以解决父类指针释放子类对象

2.都需要有具体的函数实现

虚析构和纯虚析构区别:如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

 类名::~类名(){}

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;class Animal {
public:Animal() {cout << "Animal构造函数调用" << endl;}利用虚析构可以解决父类指针释放子瑛对象时不干净的问题//virtual ~Animal() {//	cout << "Animal析构函数调用" << endl;//}//纯虚析构	需要声明也需要实现//有了纯虚析构之后,这个类也属于抽象类,无法实例化对象|virtual ~Animal() = 0;//纯虚函数virtual void speak() = 0;};Animal::~Animal() {cout << "Animal纯虚析构函数调用" << endl;
}class Cat : public Animal {
public:Cat(string name) {cout << "Cat构造函数调用" << endl;m_Name = new string(name);}~Cat() {if (m_Name!= NULL) {cout << "Cat析构函数的调用" << endl;delete m_Name;m_Name = NULL;}}virtual void speak() {cout << *m_Name <<"小猫在说话" << endl;}string* m_Name;
};void test01() {Animal* animal = new Cat("Tom");//父类指针在析构时候不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄漏animal->speak();delete animal;}int main() {test01();system("pause");return 0;}

总结:

1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

2.如果子类中没有堆区数据,,可以不写为虚析构或纯虚析构

3.拥有纯虚析构函数的类也属于抽象类

7.6 多态案例三-电脑组装

案例描述:

电脑主要组成部件为CPU(用于计算),显卡(用于显示),内存条(用于存储)

将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口

测试时组装三台不同的电脑进行工作

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;//抽象不同零件类
//抽象CPU类
class CPU {
public://抽象的计算函数virtual void calculate() = 0;
};//抽象显卡类
class VideoCard {
public://抽象的显示函数virtual void display() = 0;
};//抽象内存条类
class Memory {
public://抽象的存储函数virtual void storage() = 0;
};//电脑类
class Computer {
public:Computer(CPU* cpu, VideoCard* vc, Memory* mem) {m_cpu = cpu;m_vc = vc;m_mem = mem;}~Computer() {if (m_cpu != NULL) {delete m_cpu;m_cpu = NULL;}if (m_vc != NULL) {delete m_vc;m_vc = NULL;}if (m_mem != NULL) {delete m_mem;m_mem = NULL;}}void work() {m_cpu->calculate();m_vc->display();m_mem->storage();}private:CPU* m_cpu;//CPU零件指针VideoCard* m_vc;//显卡零件指针Memory* m_mem;//内存条零件指针};//具体厂商
//Intel
class IntelCPU : public CPU {
public:virtual void calculate() {cout << "Intel的CPU开始计算了!" << endl;}
};class IntelVideoCard : public VideoCard {
public:virtual void display() {cout << "Intel的显卡开始显示了!" << endl;}
};class IntelMemory : public Memory {
public:virtual void storage() {cout << "Intel的内存条开始存储了!" << endl;}
};//Lenovo
class LenovoCPU : public CPU {
public:virtual void calculate() {cout << "Lenovo的CPU开始计算了!" << endl;}
};class LenovoVideoCard : public VideoCard {
public:virtual void display() {cout << "Lenovo的显卡开始显示了!" << endl;}
};class LenovoMemory : public Memory {
public:virtual void storage() {cout << "Lenovo的内存条开始存储了!" << endl;}
};void test01() {CPU* intelCPU = new IntelCPU;VideoCard* intelCard = new IntelVideoCard;Memory* intelMem = new IntelMemory;cout << "第一台电脑开始工作" << endl;Computer* computer1 = new Computer(intelCPU, intelCard, intelMem);computer1->work();delete computer1;cout << "--------------------------" << endl;cout << "第二台电脑开始工作" << endl;Computer* computer2 = new Computer(new LenovoCPU,new LenovoVideoCard,new LenovoMemory);computer2->work();delete computer2;cout << "--------------------------" << endl;cout << "第三台电脑开始工作" << endl;Computer* computer3 = new Computer(new IntelCPU, new LenovoVideoCard, new IntelMemory);computer3->work();delete computer3;
}int main() {test01();system("pause");return 0;}

 

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

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

相关文章

vscode配置cc++环境要点和难点常见报错和解决方案

在VSCode中配置C/C++环境,你可以按照以下步骤进行: 下载并安装VSCode: 访问VSCode的官方网站,下载适用于你操作系统的VSCode安装包。 双击下载的安装包,按照提示进行安装。 安装C/C++扩展: 打开VSCode,点击左侧边栏的“Extensions”图标(或使用快捷键Ctrl+Shift+X)…

TypeScript 类

1. 基本用法 在 TypeScript 中&#xff0c;可以使用 class 关键字来定义类&#xff0c;然后通过 new 关键字来创建类的实例。例如&#xff1a; class Person {name: string;age: number;constructor(name: string, age: number) {this.name name;this.age age;}greet() {co…

乡村振兴的乡村人才引进与培养:引进和培养乡村人才,激发乡村发展活力,为乡村振兴提供人才保障

目录 一、引言 二、乡村人才引进与培养的重要性 &#xff08;一&#xff09;人才是乡村振兴的核心动力 &#xff08;二&#xff09;人才是乡村文化传承的载体 &#xff08;三&#xff09;人才是乡村社会治理的基石 三、乡村人才引进与培养的现状 &#xff08;一&#xf…

备战秋招c++ 【持续更新】

T1 牛牛的快递 原题链接&#xff1a;牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目类型&#xff1a;模拟 审题&确定思路&#xff1a; 1、超过1kg和不足1kg有两种不同收费方案 ---- 起步价问题 2、超出部分不足1kg的按1kg计算 ----- 向上取整 3、向上取整的实现思路…

一文掌握Java中的CyclicBarrier、CountDownLatch和Semaphore

1.CountDownLatch 1.1 介绍和用途 CountDownLatch 是一个同步助手类&#xff0c;在完成一组正在其他线程中执行的操作之前&#xff0c;它允许一个或多个线程一直等待。 1.2 工作原理 它通过一个计数器来实现&#xff0c;我们初始化 CountDownLatch 对象时指定计数器的值&am…

Android基础-Activity的介绍

在Android系统中&#xff0c;Activity是一个重要的组件&#xff0c;它承载了用户与应用之间的交互界面。以下是关于Activity的功能、作用以及生命周期的详细介绍。 Activity的功能和作用 提供用户界面&#xff1a; Activity是Android应用程序中用于表示一个屏幕或用户界面的组…

d2-crud-plus 使用小技巧(五)—— 搜索时间(或下拉列表)后,点击X清除按钮后返回值为null,导致异常

问题 使用vue2elementUId2-crud-plus&#xff0c;时间组件自动清除按钮&#xff0c;点击清除按钮后对应的值被设置为null&#xff0c;原本应该是空数组&#xff08;[]&#xff09;&#xff0c;导致数据传到后端后报错。不仅适用于搜索&#xff0c;表单一样有效果。 解决方法 …

移动端应用订阅SDK接入攻略

本文档介绍了联想应用联运移动端订阅SDK接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运移动端订阅SDK。 接入前准备 1请先与联想商务达成合作意向。 2.联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#…

谷歌开发者账号身份验证不通过?该怎么办?

我们都清楚&#xff0c;随着谷歌上架行业的快速发展&#xff0c;谷歌政策也在不断更新变化&#xff0c;对开发者账号的审核标准也在不断提升。其中一项要求就是&#xff0c;开发者账号需要进行身份验证才能发布应用。 Your identity couldnt be verified&#xff01;“我们无法…

词法与语法分析器介绍

概述 词法和语法可以使用正则表达式和BNF范式表达&#xff0c;而最终描述文法含义的事状态转换图 Lex与YACC 词法分析器Lex 词法分析词Lex&#xff0c;是一种生成词法分析的工具&#xff0c;描述器是识别文本中词汇模式的程序&#xff0c;这些词汇模式是在特殊的句子结构中…

二叉树的实现(递归实现)

前言&#xff1a;本文讲解通过递归的方式实现二叉树的一些基本接口。 目录 通过左右子树的方式实现二叉树&#xff1a; 二叉树的遍历&#xff1a; 求二叉树结点的个数&#xff1a; 二叉树所有节点的个数&#xff1a; 二叉树叶子节点的个数&#xff1a; 求第k层节点的节点…

4,八种GPIO模式

资料来源:【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 仅作个人自学笔记&#xff0c;如有冒犯&#xf…

电子阅览室解决方案

一.方案概述 “电子阅览室”概念一经提出&#xff0c;就得到了广泛的关注&#xff0c;纷纷组织力量进行探讨、研究和开发&#xff0c;进行各种模型的试验。随着数字地球概念、技术、应用领域的发展&#xff0c;电子阅览室已成为数字地球家庭的成员&#xff0c;为信息高速公路提…

深度解读 chatgpt基本原理

ChatGPT&#xff08;Generative Pre-trained Transformer&#xff09;是由OpenAI开发的一种大规模语言模型&#xff0c;基于Transformer架构&#xff0c;采用自监督学习和生成式预训练方法。以下是ChatGPT的基本原理的深度解读&#xff1a; ### 1. Transformer架构 Transforme…

深入理解C++智能指针系列(五)

引言 前面两篇介绍了std::unique_ptr的自定义删除器以及如何优化删除器的使用。本文将介绍std::unique_ptr在使用过程中的一些“奇技淫巧”。 正文 删除器和std::move std::move是将对象的所有权转移给另一个对象&#xff0c;那如果通过std::move来转移带自定义删除器的std::…

uniCloud云存储uni-cdn七牛云扩展存储-开发uniapp项目节约开发成本

为什么要使用uniCloud的扩展存储&#xff0c;那就是省钱&#xff0c;而且DCloud也一直在推uni-cdn&#xff0c;我在项目中也使用七牛云的扩展存储&#xff0c;确实是省钱&#xff0c;如果你的项目使用到大量的图片后者音视频&#xff0c;这些的算计可以帮你省不少钱。下面就通过…

OSPF的数据库表 +LSA类别

<r1>display ospf sdb 查看OSPF数据库目录 LSDB中装载了所有可以学习到的LSA; LSA--链路状态通告 一条拓扑或一条路由条目被称为一条LSA OSPF协议的数据库是本地所有LSA的集合&#xff0c;不同网络环境下将产生不同类别的LSA LSA 在共享时基于 LSU 数据包传递…

【状态机动态规划】3129. 找出所有稳定的二进制数组 I

本文涉及知识点 动态规划汇总 LeetCode 3129. 找出所有稳定的二进制数组 I 给你 3 个正整数 zero &#xff0c;one 和 limit 。 一个 二进制数组 arr 如果满足以下条件&#xff0c;那么我们称它是 稳定的 &#xff1a; 0 在 arr 中出现次数 恰好 为 zero 。 1 在 arr 中出现…

leetCode.83. 删除排序链表中的重复元素

leetCode.83. 删除排序链表中的重复元素 代码 class Solution { public:ListNode* deleteDuplicates(ListNode* head) {auto p head;while(p){auto q p->next;while(q && p->val q->val) q q->next;if(p->next q) p p->next;else p->next …

dp背包问题

英雄联盟游戏中新出n个英雄&#xff0c;用长度为n的教组 costs 表示每个英雄的定价&#xff0c;其中 costs[i]表示第i个英雄的点券价格。假如你一共有coins点券可以用于消费&#xff0c;且想要买尽可能多的英雄并日选择英雄按costs[i]给出顺序获取。给你价格数组 costs 和金币量…