【C++核心编程(四)】

一、继承

继承是面向对象三大特性之一。

有些类与类之间存在特殊的关系,例如下图中:

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

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

1.1、继承的基本语法

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

//普通实现页面
//Java
class Java
{
public:void header(){cout << "首页、公开课、登陆、注册...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、C++、Python...(公共分类列表)" << endl;}void content(){cout << "Java学科视频" << endl;}
};//Python
class Python
{
public:void header(){cout << "首页、公开课、登陆、注册...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、C++、Python...(公共分类列表)" << endl;}void content(){cout << "Python学科视频" << endl;}
};//C++
class CPlusPlus
{
public:void header(){cout << "首页、公开课、登陆、注册...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、C++、Python...(公共分类列表)" << endl;}void content(){cout << "C++学科视频" << endl;}
};//继承实现上述代码 - 好处:减少重复的代码
//语法:class 子类(派生类) : 继承方式 父类(基类)//公共页面类
class BasePage
{
public:void header(){cout << "首页、公开课、登陆、注册...(公共头部)" << endl;}void footer(){cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;}void left(){cout << "Java、C++、Python...(公共分类列表)" << 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 CPlusPlus :public BasePage
{
public:void content(){cout << "C++学科视频" << endl;}
};void test01()
{cout << "Java页面如下:" << endl;Java java;java.header();java.footer();java.left();java.content();cout << "---------------------" << endl;cout << "Python页面如下:" << endl;Python python;python.header();python.footer();python.left();python.content();cout << "---------------------" << endl;cout << "C++页面如下:" << endl;CPlusPlus c;c.header();c.footer();c.left();c.content();
}int main()
{test01();system("pause");return 0;
}

总结:

继承的好处:可以减少重复的代码

class A : public B;

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

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

一类是从基类继承过来的,一类是自己增加的成员。

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

1.2、继承方式

继承的语法: class 子类 : 继承方式 父类

继承方式一共有三种: 

·公共继承

·保护继承

·私有继承

1.3、继承中的对象模型

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

class Base
{
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son :public Base
{
public:int m_D;
};void test01()
{//父类中所有非静态成员属性都会被子类继承下去//父类中的私有成员属性是被编译器给隐藏了,因此访问不到但是确实是被继承下去了cout << "size of Son = " << sizeof(Son) << endl;
}int main()
{test01();system("pause");return 0;
}

利用开发人员命令提示工具查看对象模型:

①跳转盘符 - C:

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

③查看命名

④cl(l - 小写L) /d1 reportSingleClassLayout类名 文件名(按tab键自动补齐)

结论:父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到。

1.4、继承中构造和析构顺序

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

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

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()
{//Base b;//继承中的构造和析构的顺序:先构造父类,再构造子类,析构的顺序与构造的顺序相反Son s;
}int main()
{test01();system("pause");return 0;
}

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

1.5、继承同名成员处理方式

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

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

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

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.当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数。

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

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

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

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

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

class Base
{
public:static int m_A;static void func(){cout << "Base.static.func()" << endl;}static void func(int a){cout << "Base.static.func(int a)" << endl;}
};
int Base::m_A = 200;class Son :public Base
{
public:static int m_A;static void func(){cout << "Son.static.func()" << endl;}
};
int Son::m_A = 100;//同名静态成员属性
void test01()
{//1.通过对象访问cout << "通过对象访问:" << endl;Son s;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()
{//1.通过对象访问cout << "通过对象访问:" << endl;Son s;s.func();s.Base::func();//2.通过类名访问cout << "通过类名方式访问:" << endl;Son::func();Son::Base::func();//子类出现和父类同名的静态成员函数,也会隐藏父类中所有同名的静态成员函数//如果想访问父类中被隐藏的同名成员,需要加作用域Son::Base::func(100);
}int main()
{test01();test02();system("pause");return 0;
}

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

1.7、多继承语法

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

语法: class 子类 : 继承方式 父类1 , 继承方式 父类2...

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

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

class Base1
{
public:Base1(){m_A = 100;}int m_A;
};class Base2
{
public:Base2(){m_A = 200;}int m_A;
};//子类继承Base1和Base2
//语法: class 子类 : 继承方式 父类1 , 继承方式 父类2 ...
class Son :public Base1 , public Base2
{
public:int m_C;int m_D;Son(){m_C = 300;m_D = 400;}
};void test01()
{Son s;cout << "size of (Son) = " << sizeof(s) << 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;
}

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

1.8、菱形继承

菱形继承概念:

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

典型的菱形继承案例:

菱形继承问题:

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

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

//动物类
class Animal
{
public:int m_Age;
};//利用虚继承可以解决菱形继承带来的问题
//在继承之前加上关键字virtual变为虚继承
//Animal类称为虚基类
//羊类
class Sheep :virtual public Animal
{
public:};//驼类
class Tuo :virtual public Animal
{
public:};//羊驼类
class SheepTuo :public Sheep , public Tuo
{
public:};void test01()
{SheepTuo st;st.Sheep::m_Age = 18;st.Tuo::m_Age = 28;//当菱形继承时,两个父类拥有相同数据,需要加以作用域区分cout << "Sheep::m_Age = " << st.Sheep::m_Age << endl;cout << "Tuo::m_Age = " << st.Tuo::m_Age << endl;cout << "st.m_Age = " << st.m_Age << endl;//这份数据我们明确只需要有一份即可,菱形继承导致数据有两份,资源浪费
}int main()
{test01();system("pause");return 0;
}

总结:

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

·利用虚继承可以解决菱形继承问题。

二、多态 

2.1、多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类:
·静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名

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

静态多态和动态多态区别:
·静态多态的函数地址早绑定 - 编译阶段确定函数地址
·动态多态的函数地址晚绑定 - 运行阶段确定函数地址 

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

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

总结:

多态满足条件:
·有继承关系
·子类重写父类中的虚函数

多态使用条件:
·父类指针或引用指向子类对象
重写: 函数返回值类型、函数名、参数列表完全一致称为重写。

2.2、多态案例一 - 计算器类

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

多态的优点:
·代码组织结构清晰
·可读性强
·利于前期和后期的扩展以及维护

class Calculator
{
public:int m_Num1;int m_Num2;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;}//如果想要扩展新的功能需要修改源码//在真正的开发中提倡:开闭原则 - 对扩展进行开放,对修改进行关闭}
};void test01()
{//创建计算器对象Calculator cal;cal.m_Num1 = 10;cal.m_Num2 = 10;cout << cal.m_Num1 << " + " << cal.m_Num2 << " = " << cal.getResult("+") << endl;cout << cal.m_Num1 << " - " << cal.m_Num2 << " = " << cal.getResult("-") << endl;cout << cal.m_Num1 << " * " << cal.m_Num2 << " = " << cal.getResult("*") << endl;
}//利用多态实现计算器
//实现计算器的抽象类
class AbstractCalculator
{
public:int m_Num1;int m_Num2;virtual int getResult(){return 0;}
};//加法计算器类
class AddCalculator :public AbstractCalculator
{int getResult(){return m_Num1 + m_Num2;}};//减法计算器类
class SubCalculator :public AbstractCalculator
{int getResult(){return m_Num1 - m_Num2;}};//乘法计算器类
class MulCalculator :public AbstractCalculator
{int getResult(){return m_Num1 * m_Num2;}};void test02()
{//多态使用条件 - 父类指针或者引用指向子类对象//加法运算AbstractCalculator* abs = new AddCalculator;abs->m_Num1 = 100;abs->m_Num2 = 100;cout << abs->m_Num1 << " + " << abs->m_Num2 << " = " << abs->getResult() << endl;//用完后记得销毁delete abs;//减法运算abs = new SubCalculator;abs->m_Num1 = 100;abs->m_Num2 = 100;	cout << abs->m_Num1 << " - " << abs->m_Num2 << " = " << abs->getResult() << endl;delete abs;//乘法运算abs = new MulCalculator;abs->m_Num1 = 100;abs->m_Num2 = 100;cout << abs->m_Num1 << " * " << abs->m_Num2 << " = " << abs->getResult() << endl;delete abs;
}int main()
{//test01();test02();system("pause");return 0;
}

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

2.3、纯虚函数和抽象类

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

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

纯虚函数语法: virtual 返回值类型 函数名(数列表) = 0;

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

抽象类特点:

·无法实例化对象
·子类必须重写抽象类中的纯虚函数,否则也属于抽象类

2.4、多态案例二 - 制作饮品

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

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

class AbstractDrinking
{
public://煮水virtual void Boil() = 0;//冲泡virtual void Brew() = 0;//倒入杯中virtual void PourInCup() = 0;//加入辅助佐料virtual void PutSomthing() = 0;//制作饮品void makeDrink(){Boil();Brew();PourInCup();PutSomthing();}
};//制作咖啡
class Coffee : public AbstractDrinking
{
public://煮水void Boil(){cout << "煮农夫山泉水" << endl;}//冲泡void Brew(){cout << "冲泡咖啡" << endl;}//倒入杯中void PourInCup(){cout << "倒入咖啡杯中" << endl;}//加入辅助佐料void PutSomthing(){cout << "加入糖和牛奶" << endl;}
};//制作茶叶
class Tea : public AbstractDrinking
{
public://煮水void Boil(){cout << "煮冰露矿泉水" << endl;}//冲泡void Brew(){cout << "冲泡茶叶" << endl;}//倒入杯中void PourInCup(){cout << "倒入茶壶中" << endl;}//加入辅助佐料void PutSomthing(){cout << "加入柠檬和枸杞" << endl;}
};//制作函数
void doDrink(AbstractDrinking* abs)//AbstractDrinking* abs = new Coffee;
{abs->makeDrink();delete abs;//释放堆区数据
}void test01()
{//制作咖啡doDrink(new Coffee);cout << "--------------" << endl;//制作茶doDrink(new Tea);
}int main()
{test01();system("pause");return 0;
}

2.5、虚析构和纯虚析构

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

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

虚析构和纯虚析构共性:

·可以解决父类指针释放子类对象
·都需要有具体的函数实现

虚析构和纯虚析构区别: 

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

虚析构语法: virtual ~类名(){}

纯虚析构语法: virtual ~类名() = 0;

类名::~类名(){}

class Animal
{
public://纯虚函数virtual void speak() = 0;Animal(){cout << "Animal的构造函数" << endl;}//利用虚析构可以解决父类指针释放子类对象时不干净的问题//virtual ~Animal()//{//	cout << "Animal的虚析构函数!" << endl;//}//纯虚析构 - 需要声明也需要实现//有了纯虚析构之后,这个类也属于抽象类,无法实例化对象virtual ~Animal() = 0;
};Animal::~Animal()
{cout << "Animal的纯虚析构函数!" << endl;
}class Cat :public Animal
{
public:Cat(string name){cout << "Cat的构造函数" << endl;m_Name = new string(name);}~Cat(){cout << "Cat的析构函数" << endl;if (m_Name != NULL){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;
}

可以看到上述代码如若按照图片来写的结果是,Cat类在堆区创建了数据理应在析构函数中释放,但是Animal类的指针在析构时并不会调用子类对象的析构函数,所以我们要用虚析构来解决问题,如下:

 

这样我们就可以把在子类创建的堆区数据释放干净了。

总结:

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

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

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

2.6、多态案例三 - 电脑组装

案例描述:

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

将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如lntel厂商和Lenovo厂商;

创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口;

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

//抽象不同零件类
//抽象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;}//提供工作函数void work(){//让零件工作,调用接口m_cpu->calculate();m_vc->display();m_mem->storage();}//提供析构函数来释放3个电脑零件~Computer(){//释放cpu零件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;}}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()
{cout << "------第一台电脑-------" << endl;//第一台电脑零件CPU* intelCPU = new IntelCPU;VideoCard* intelCard = new IntelVideoCard;Memory* intelMem = new IntelMemory;//创建第一台电脑Computer* computer1 = new Computer(intelCPU, intelCard, intelMem);computer1->work();delete computer1;cout << "------第二台电脑-------" << endl;//第二台电脑组装Computer* computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);computer2->work();delete computer2;cout << "------第三台电脑-------" << endl;Computer* computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);computer3->work();delete computer3;
}int main()
{test01();system("pause");return 0;
}

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

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

相关文章

python统计分析——箱线图(plt.boxplot)

参考资料&#xff1a;用python动手学统计学 使用matplotlib.pyplot.boxplot()函数绘制箱线图 import numpy as np import pandas as pd from matplotlib import pyplot as pltdata_set1np.array([2,3,3,4,4,4,4,5,5,6]) data_set2np.array([[2,3,3,4,4,4,4,5,5,6],[5,6,6,7,7…

十八:爬虫-JS逆向(下)

一&#xff1a;AES与DES DES对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥&#xff0c;信息的发送者。和信息的接收者在进行信息的传输与处理时&#xff0c;必须共同持有该密钥(称为对称密码),是一种对称加密算法。一般来说加密用的是encrypt()函…

[redis] redis的安装,配置与简单操作

一、缓存的相关知识 1.1 缓存的概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度&#xff0c;在中间对速度较慢的一方起到加速作用&#xff0c;比如CPU的一级、二级缓存是保存了CPU最近经常访问的数据&#xff0c;内存是保存CPU经常访问硬盘的数据&#xff0c;而且…

给您的应用添加弹窗

概述 在我们日常使用应用的时候&#xff0c;可能会进行一些敏感的操作&#xff0c;比如删除联系人&#xff0c;这时候我们给应用添加弹窗来提示用户是否需要执行该操作&#xff0c;如下图所示&#xff1a; 弹窗是一种模态窗口&#xff0c;通常用来展示用户当前需要的或用户必须…

OpenVINS学习6——VioManagerHelper.cpp,VioManagerOptions.h学习与注释

前言 VioManager类里还有VioManagerHelper.cpp,VioManagerOptions.h这两个文件&#xff0c;也包含了一些函数&#xff0c;这次接着看这个 。 整体分析 void VioManager::initialize_with_gt(Eigen::Matrix<double, 17, 1> imustate) 给一个状态&#xff0c;然后初始化…

学生信息管理系统(录入、查找、删除、修改、排序、统计等功能实现)超详细完整代码,建议保存。

许多老师都会布置Python期末大作业&#xff0c;作业题目很多就是学生信息管理系统&#xff0c;以前都是练习小题目&#xff0c;几十行代码就能搞定&#xff0c;而完整的写完这个系统我用了差不多400行代码。完整写完这个系统&#xff0c;是对一个学期所学知识的进一步深入了解于…

【知识点】:ECMAScript简介及特性

一.简介 什么是ECMAScript&#xff1f; ECMAScript是由网景的布兰登艾奇开发的一种脚本语言的标准化规范&#xff1b;最初命名为Mocha&#xff0c;后来改名为LiveScript&#xff0c;最后重命名为JavaScript。1995年12月&#xff0c;升阳与网景联合发表了JavaScript。1996年11月…

Arduino开发实例-欧姆龙E3Z-D61光电传感器

欧姆龙E3Z-D61光电传感器 文章目录 欧姆龙E3Z-D61光电传感器1、E3Z-D61光电传感器介绍2、硬件准备及接线3、代码实现1、E3Z-D61光电传感器介绍 Omran 光电传感器可用于检测 5 至 100 毫米距离内的障碍物和物体。 传感器上有一个 LED,它始终熄灭,并在检测到障碍物时亮起。 您…

Open CASCADE学习|Draw Harness

目录 显示长方体 提供帮助信息 执行文件 记录交互式命令 使用getsourcefile可以快速查找到Tcl命令对应的C源文件 在Tcl中内置了一些变量&#xff0c;并赋予了一定的功能。内置变量列表如下&#xff1a; 退出 加载插件 在屏幕显示变量 返回绘图变量信息 视图 mu, md…

06、Kafka ------ 各个功能的作用解释(ISR 同步副本、非同步副本、自动创建主题、修改主题、删除主题)

目录 CMAK 各个功能的作用解释★ ISR副本 (同步副本&#xff09;★ 非同步副本★ 自动创建主题★ 修改主题★ 删除主题 CMAK 各个功能的作用解释 ★ ISR副本 (同步副本&#xff09; 简单来说 &#xff0c;ISR 副本 就是 Kafka 认为与 领导者副本 同步的副本。 ISR&#xff0…

DataFunSummit:2023年知识图谱在线峰会-核心PPT资料下载

一、峰会简介 AIGC&#xff0c;ChatGPT以及发布的GPT-4相信已经给大家带来足够的冲击&#xff0c;那么对于知识图谱的应用产生哪些变化和变革&#xff1f;知识图谱在其中如何发挥作用呢&#xff1f;通过LLM是否有可能辅助创建通用大规模知识图谱&#xff1f;AIGC时代下行业知识…

win10下vscode+cmake编译C代码操作详解

0 工具准备 1.Visual Studio Code 1.85.1 2.cmake 3.24.01 前言 当我们只有一个.c文件时直接使用vscodeCode Runner插件即可完成编译&#xff0c;如果我们的工程很复杂包含多个.c文件时建议使用cmake来生成对应的make&#xff0c;指导编译器完成编译&#xff0c;否则会提示各…