设计模式-单例模式工厂模式

3.1 单例模式

1.概念

用类来实现单例。由于某种需要,要保证一个类在程序的生命周期中只有一个实例,并且提供该实例的全局访问方法。

2.结构三要素

1)私有的静态对象属性private static instance,它的类型就是当前类的对象,静态的特性决定了程序一启动就要初始化完成当前对象的构造。

2)私有的构造函数(保证在程序中,无法通过new的方式来创建对象实例,只能用于类内部创建该单例对象)

3)公有的,静态的(类可以直接访问,因为无法创建对象,所以不能用对象来访问非静态的成员函数。),访问该实例对象的方法public static Singleton getInstance(){}

3.实现——饿汉式(代码见vs)

饿汉式就是应用程序刚启动时,不管外部有没有调用该类的实例方法,该类的实例就已经创建好了。以空间换时间。

优点:写法简单,在多线程下能保证单例实例的唯一性,运行效率高。

缺点:在外部未使用到该类时,类的实例已经创建,若类实例的创建比较消耗系统资源,并且外部一直没有调用该实例,造成资源浪费。

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;//饿汉式
class Singleton
{
private:static Singleton* instance;//1)私有的静态对象属性Singleton() {};//2)私有的构造函数
public:static Singleton* getInstance()//3)公有的,静态的访问该单例的方法{return instance;}
};
//实例化类的静态成员,要在类外初始化
Singleton* Singleton::instance = new Singleton();//程序一启动,单例马上就创建出来了,并且在整个程序生命周期,只有一份
void test01()
{//测试一下,单例是否生效Singleton* ins=Singleton::getInstance();Singleton* ins2=Singleton::getInstance();//接下来通过查看ins和ins2的地址,就可以判断是否为同一个对象cout << ins << "=" << ins2 << endl;
}

4.实现——懒汉式(代码见vs)

懒汉式就是应用程序刚启动时,并不创建实例,当外部调用该类的实例或者该类实例方法时,才创建该类的实例。是以时间换空间。

优点:实例在被使用时创建,可以节省系统资源,体现延迟加载的思想。

缺点:系统刚启动且未被外部调用时,实例没有创建,如果同时有多个线程调用实例方法getInstance,可能会产生多个实例。在多线程下,不能保证单例实例的唯一性,需使用同步,同步会导致多线程下争夺锁资源,降低运行效率。

//懒汉式
class Singleton_Lan
{
private:static Singleton_Lan* instance;Singleton_Lan() {};
public:static Singleton_Lan* getInstance(){//把单例的创建时机放到这里,有人调用这个函数的时候,就要创建了if (instance==nullptr)//加个判断,当单例没有被创建的时候,才去创建它{instance = new Singleton_Lan();//这里创建出单例}return instance;}
};
void test02()
{//测试一下,单例是否生效Singleton_Lan* ins = Singleton_Lan::getInstance();Singleton_Lan* ins2 = Singleton_Lan::getInstance();//接下来通过查看ins和ins2的地址,就可以判断是否为同一个对象cout << ins << "=" << ins2 << endl;
}
Singleton_Lan* Singleton_Lan::instance = nullptr;//懒汉式,程序启动的时候不创建单例,而是设置为空

5.验证懒汉模式下——多线程不安全问题(代码见vs)

//多线程下,懒汉模式不安全,无法保证单例的实现
class Singleton_Duo
{
private:static Singleton_Duo* instance;Singleton_Duo() { this_thread::sleep_for(chrono::milliseconds(500)); };//构造的时候加延时,这个时候就可以发现问题
public:static Singleton_Duo* getInstance(){if (instance==nullptr)//这个判断,在多线程下是不可靠的{instance = new Singleton_Duo();}return instance;}
};
Singleton_Duo* Singleton_Duo::instance = nullptr;
//准备线程绑定的函数
void threadFunc()
{Singleton_Duo* ins=Singleton_Duo::getInstance();cout << this_thread::get_id() << ":" << ins << endl;
}
void test03()
{thread t3[3];for (int i = 0; i < 3; i++){t3[i] = thread(threadFunc);}for (int i = 0; i < 3; i++){t3[i].join();}
}
//如果换成饿汉式单例,多线程下也是安全的
void threadFunc_e()
{Singleton* ins = Singleton::getInstance();cout << this_thread::get_id() << ":" << ins << endl;
}
void test04()
{thread t3[3];for (int i = 0; i < 3; i++){t3[i] = thread(threadFunc_e);}for (int i = 0; i < 3; i++){t3[i].join();}
}

6.懒汉式——加锁模式(代码见vs)

//通过加锁,解决多线程下懒汉式单例的问题
mutex mut;//锁对象
class Singleton_Duo_Suo
{
private:static Singleton_Duo_Suo* instance;Singleton_Duo_Suo() { this_thread::sleep_for(chrono::milliseconds(500)); }
public:static Singleton_Duo_Suo* getInstance(){mut.lock();//加锁if (instance==nullptr){instance = new Singleton_Duo_Suo();}mut.unlock();//解锁return instance;}
};
Singleton_Duo_Suo* Singleton_Duo_Suo::instance = nullptr;
//加锁后的懒汉式,多线程绑定的函数
void threadFunc_suo()
{Singleton_Duo_Suo* ins = Singleton_Duo_Suo::getInstance();cout << this_thread::get_id() << ":" << ins << endl;
}
void test05()
{thread t3[3];for (int i = 0; i < 3; i++){t3[i] = thread(threadFunc_suo);}for (int i = 0; i < 3; i++){t3[i].join();}
}

7.单例释放问题

一般单例模式不用考虑内存释放问题,因为单个对象占用的空间不大。如果手动释放,会影响调用这个对象的资源,并且bug很难找。

如果非要手动释放,可以用这两种方式实现:

1)调用delete释放内存

2)单例中提供静态方法用于释放内存

8.饿汉式——局部静态变量实现单例(代码见vs)

使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,就是把上面的第一要素的对象属性放在getInstance函数中去创建。它的作用域就是getInstance函数中。

不用担心单例销毁的问题,静态局部变量离开作用域后,不会马上被销毁,仍然驻留在内存中,只是无法被访问,当再次调用getInstance函数的时候,就能重新访问这个变量。只有当程序结束时,该变量才会被销毁,从内存中释放,此时,单例对象也被回收了。静态变量跟程序的生命周期一致。

不用担心多线程不安全问题,因为在编译器层面,本身就是支持静态局部变量的线程安全的,所以使用静态局部变量来保存单例,也是安全的。

优点:解决线程不安全问题;解决单例析构问题;代码简洁易懂。

//局部静态变量实现单例,可以保证多线程安全
class Singleton_Jubu
{
private:Singleton_Jubu(){}
public:static Singleton_Jubu* getInstance(){//定义一个局部静态变量来指向单例对象static Singleton_Jubu* instance_jubu = new Singleton_Jubu();return instance_jubu;}
};
void test06()
{Singleton_Jubu* ins_jubu = Singleton_Jubu::getInstance();Singleton_Jubu* ins2_jubu = Singleton_Jubu::getInstance();cout << ins_jubu << "=" << ins2_jubu << endl;
}//多线程下,验证局部静态变量单例的安全性
class Singleton_Jubu_Duo
{
private:Singleton_Jubu_Duo() { this_thread::sleep_for(chrono::milliseconds(500)); }
public:static Singleton_Jubu_Duo* getInstance(){static Singleton_Jubu_Duo* instance_jubu = new Singleton_Jubu_Duo();return instance_jubu;}
};
void threadFunc_jubu()
{Singleton_Jubu_Duo* ins = Singleton_Jubu_Duo::getInstance();cout << this_thread::get_id() << ":" << ins << endl;
}
void test07()
{thread t3[3];for (int i = 0; i < 3; i++){t3[i] = thread(threadFunc_jubu);}for (int i = 0; i < 3; i++){t3[i].join();}
}

9.单例总结

优点

1. 在内存中只有一个对象,节省内存空间。

2. 避免频繁的创建销毁对象,可以提高性能。

缺点

1. 没有接口,扩展困难。

2. 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

应用场景

1. 要求生成唯一序列号的环境。

2. 在整个项目中需要一个共享访问点或共享数据。

3. 创建一个对象需要消耗的资源过多。

4. 需要定义大量的静态常量和静态方法。如math类

注意事项

在高并发多线程情况下,注意普通单例模式的线程同步问题。

3.2 工厂模式

1.概念

在开发过程中完成某个任务时,都是通过调用实例对象的方法来实现的,需要一个准备动作(实例化对象)。如果一个类在实例化对象时操作很复杂(需要读配置文件,获取参数),可以用工厂模式,让用户和类分离,不要让用户操心对象如何创建的问题。该模式用于封装和管理对象的创建,是一种创建型模式。

工厂模式有三种:

简单工厂模式:工厂根据用户参数可以生产任意产品(产品即对象),工厂只有一层,没有抽象层,产品有抽象层和具体层。

工厂方法模式:工厂增加一个抽象层,派生出具体的工厂,具体的工厂只能生产具体的某个产品,客户不需要传参,只需要使用不同的工厂就能生产对应的产品。

抽象工厂模式:工厂和产品都有抽象层和具体层,最大的改变是具体层的每个工厂,都可以生产全部的产品,这些产品根据由哪个工厂生产的划分为不同的产品族,一个工厂的产品都属于一个产品族。

2.简单工厂模式(代码见vs)

简单工厂模式也被称为静态工厂模式;消费和生产完全分开,客户端只需要知道自己需要什么产品,如何来使用产品就可以了,具体的产品生产任务由具体的工厂类来实现。工厂类根据传进来的参数生产具体的产品供消费者使用。

#include <iostream>
using namespace std;//简单工厂
//父类,水果类,抽象类
class AbsFruit
{
public:virtual void showName() = 0;//纯虚函数,接口
};
//具体产品类,苹果
class Apple :public AbsFruit
{
public:virtual void showName() { cout << "我是苹果" << endl; }
};
//具体产品类,桃子
class Peach :public AbsFruit
{
public:virtual void showName() { cout << "我是桃子" << endl; }
};
//具体产品类,香蕉
class Banana :public AbsFruit
{
public:virtual void showName() { cout << "我是香蕉" << endl; }
};
//简单工厂类
class SimpleFactory
{
public:AbsFruit* createFruit(string str)//根据参数决定生产什么产品{if (str=="apple"){return new Apple();}else if (str=="peach"){return new Peach();}else if (str=="banana"){return new Banana();}}
};
void test01()
{SimpleFactory sf = SimpleFactory();AbsFruit* a=sf.createFruit("apple");a->showName();AbsFruit* b = sf.createFruit("banana");b->showName();delete a;delete b;
}

简单工厂模式的构成:

具体的工厂角色:Factory;在工厂中根据参数不同生产出不同的产品;

抽象的产品角色:Product;在抽象产品类中声明接口,在具体的产品类中实现;

具体的产品角色:ProductA 和ProdcutB;在具体的类中实现抽象产品类的接口,也可以实现自己的业务逻辑。

简单工厂模式的总结

优点

工厂类包含必要的逻辑判断,可以根据用户需求动态实例化相关的类。

客户端可以免除直接创建产品对象的职责,去除了与具体产品的依赖。工厂和产品的职责区分明确。

缺点

增加产品,需要修改工厂类,扩展困难,不符合开闭原则。

客户创建实例对象时需要传入参数,需要记住参数的格式,比较麻烦。

应用场景

对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

3.工厂方法模式(也可以称为复杂工厂)(代码见vs)

简单工厂方法违背了对扩展开放的原则,添加产品需要修改工厂类,并且高度依赖用户输入的参数。工厂方法模式是在简单工厂模式的基础上,工厂添加了一个抽象层。将工厂共同的动作抽象出来,作为抽象类,而具体的行为由子类去实现,让子类去决定生产什么样的产品。

//工厂方法模式
//抽象层工厂
class AbsFactory
{
public:virtual AbsFruit* createFruit() = 0;
};
//苹果工厂
class AppleFactory :public AbsFactory
{
public:virtual AbsFruit* createFruit() { return new Apple(); }
};
//桃子工厂
class PeachFactory :public AbsFactory
{
public:virtual AbsFruit* createFruit() { return new Peach(); }
};
//香蕉工厂
class BananaFactory :public AbsFactory
{
public:virtual AbsFruit* createFruit() { return new Banana(); }
};
void test02()
{//想要什么产品,就需要什么工厂AbsFactory* apple_fac = new AppleFactory();//创建一个苹果工厂AbsFruit* apple=apple_fac->createFruit();//生产苹果apple->showName();AbsFactory* banana_fac = new BananaFactory();AbsFruit* banana = banana_fac->createFruit();banana->showName();delete apple_fac;delete banana_fac;delete apple;delete banana;
}

工厂方法模式总结

工厂方法模式 = 简单工厂模式 + 开闭原则

优点

继承了简单工厂模式的优点。

系统的可扩展性变得更好,符合开闭原则。

降低了用户的使用难度,不用考虑简单工厂的传参问题。

缺点

系统中的类是成对增加,增加了系统的复杂度和理解度。

应用场景

在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式。

4.抽象工厂模式(代码见vs)

//抽象工厂
//抽象苹果
class AbsApple
{
public:virtual void showName() = 0;//纯虚函数,接口
};
//中国苹果
class ChinaApple :public AbsApple
{
public:virtual void showName() { cout << "中国苹果" << endl; }
};
//日本苹果
class JapApple :public AbsApple
{
public:virtual void showName() { cout << "日本苹果" << endl; }
};
//抽象桃子
class AbsPeach
{
public:virtual void showName() = 0;//纯虚函数,接口
};
//中国桃子
class ChinaPeach :public AbsPeach
{
public:virtual void showName() { cout << "中国桃子" << endl; }
};
//日本桃子
class JapPeach :public AbsPeach
{
public:virtual void showName() { cout << "日本桃子" << endl; }
};
//抽象工厂
class AbsFactory_Abs
{
public:virtual AbsApple* createApple() = 0;virtual AbsPeach* createPeach() = 0;
};
//中国工厂
class ChinaFactory :public AbsFactory_Abs
{virtual AbsApple* createApple() { return new ChinaApple(); }virtual AbsPeach* createPeach() { return new ChinaPeach(); }
};
//日本工厂
class JapFacotry :public AbsFactory_Abs
{virtual AbsApple* createApple() { return new JapApple(); }virtual AbsPeach* createPeach() { return new JapPeach(); }
};
void test03()
{//抽象工厂,每个工厂都能生产所有的产品AbsFactory_Abs* chinaFac = new ChinaFactory();//中国工厂AbsApple* china_apple = chinaFac->createApple();//生产中国苹果AbsPeach* china_peach = chinaFac->createPeach();//生产中国桃子china_apple->showName();//使用产品china_peach->showName();//使用产品delete chinaFac;delete china_apple;delete china_peach;AbsFactory_Abs* japFac = new JapFacotry();//日本工厂AbsApple* jap_apple = japFac->createApple();//生产日本苹果AbsPeach* jap_peach = japFac->createPeach();//生产日本桃子jap_apple->showName();//使用产品jap_peach->showName();//使用产品delete japFac;delete jap_apple;delete jap_peach;
}

抽象工厂总结

优点

1、抽象工厂模式隔离了具体产品的生产,使得客户并不需要知道什么产品被创建,一个工厂可以创建各种产品。

2、当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。可以理解为系统给用户提供了很多套相似的产品,每一套产品属于一个产品族,大体功能类似,但有一些细微的差别,比如同样的软件功能,但由于不同国家地区的法律法规和风俗不同,需要做出调整。

3、增加新的工厂族和产品族很方便,只需要添加新的工厂族即可,无须修改已有系统,符合“开闭原则”。

缺点

增加新的产品等级很复杂,比如增加一个橘子产品,需要修改抽象工厂和所有的具体工厂类,违反了开闭原则。

应用场景

适用于产品种类多的场合,主要用于创建一组相关的产品(属于同一个产品族),为它们提供创建的接口。注意事项:产品族易扩展,产品等级难扩展。

5.工厂模式总结

简单工厂模式:

产品有抽象层和具体层,工厂没有抽象层。工厂用来生产同一等级结构中的具体任意产品。对于增加新的产品,就要修改工厂类(需要根据参数决定生产什么产品)。符合单一职责原则。不符合开闭原则。客户传参麻烦。

工厂方法模式:

产品有抽象层和具体层,工厂也有抽象层和具体层,具体工厂用来生产固定产品。支持增加任意产品,但是增加一个产品就要增加一对(产品类和工厂类)。新增产品时不需要更改已有的工厂。符合单一职责原则、符合开闭原则。但是引入了复杂性。

抽象工厂模式 :

工厂和产品都有抽象层,工厂可以生产各种产品,不仅仅是固定的产品,这些产品都来自于同一个产品族。增加工厂族很容易,产品族容易扩展。但是增加新产品很难,需要修改已有的各个工厂族以及抽象工厂。符合单一职责原则,部分符合开闭原则,降低了复杂性。

6.练习(工厂方法模式)

#include <iostream>using namespace std;//抽象鼠标类
class Mouse
{
public:virtual void showName() = 0;
};
//dellmouse
class DellMouse :public Mouse
{
public:virtual void showName() { cout << "dellMouse" << endl; }
};
//hpMouse
class HpMouse :public Mouse
{virtual void showName() { cout << "hpMouse" << endl; }
};
//抽象工厂
class MouseFactory
{
public:virtual Mouse* createdellmouse() = 0;};
//dellfactory
class DellFactory :public MouseFactory
{
public:virtual DellMouse* createdellmouse() { return new DellMouse; }
};
//hpfactory
class HpFactory :public MouseFactory
{
public:virtual HpMouse* createhpmouse() { return new HpMouse; }
};void test1()
{MouseFactory* dellmouse = new DellFactory();Mouse* dell = dellmouse->createdellmouse();dell->showName();delete dellmouse;delete dell;
}

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

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

相关文章

EMC技术

目录 EMC 天线效应 公式 措施 EMC测试 展频技术 如何展频 OTA测试 EMC 三大要素&#xff1a;干扰源、传输介质、敏感设备。 EMI&#xff1a;Electromagnetic Interference&#xff0c;电磁干扰。 EMS&#xff1a;Electro Magnetic Susceptibility&#xff0c;电磁抗扰…

Centos7安装RabbitMQ

文章目录 Centos7安装RabbitMQ第一步、安装任何软件包之前&#xff0c;建议使用以下命令更新软件包和存储库第二步、Erlang在默认的YUM存储库中不可用&#xff0c;因此您将需要安装EPEL存储库第三步、RabbitMQ是基于Erlang&#xff08;面向高并发的语言&#xff09;语言开发&am…

语音测试(一)ffmpeg视频转音频

视频转音频 下载ffmpeg工具进入bin目录cmd进入控制台输入命令 ffmpeg.exe -i ./视频.mp4 ./音频.wav命令说明 ffmpeg -i input.mp4 output.mkv FFmpeg 可能会尝试自动选择合适的编码器对视频和音频进行重新编码&#xff0c;以便适应 MKV 格式的要求ffmpeg -i input.mp4 -c c…

Python | Leetcode Python题解之第390题消除游戏

题目&#xff1a; 题解&#xff1a; class Solution:def lastRemaining(self, n: int) -> int:a1 1k, cnt, step 0, n, 1while cnt > 1:if k % 2 0: # 正向a1 stepelse: # 反向if cnt % 2:a1 stepk 1cnt >> 1step << 1return a1

心觉:如何用一颗心改变世界和自己

关于如何开发自己的潜意识开发的底层逻辑和注意事项 我这里就不赘述了&#xff0c;可以看我前面的文章 今天主要讲一下&#xff0c;如何让我们祈祷的作用发挥到极致 这里提到了祈祷&#xff0c;其实就是正念 把自己的梦想&#xff0c;目标&#xff0c;愿望通过积极的语言 …

数据预处理与协同过滤推荐算法——从数据清洗到个性化电影推荐

推荐系统在现代应用中占据了重要地位&#xff0c;尤其在电影、音乐等个性化内容推荐中广泛使用。本文将介绍如何使用数据预处理、特征工程以及多种推荐算法&#xff08;包括协同过滤、基于内容的推荐、混合推荐等&#xff09;来实现电影推荐系统。通过Pandas、Scikit-learn、Te…

探索PDF的奥秘:pdfrw库的神奇之旅

文章目录 探索PDF的奥秘&#xff1a;pdfrw库的神奇之旅背景&#xff1a;为何选择pdfrw&#xff1f;pdfrw是什么&#xff1f;如何安装pdfrw&#xff1f;五个简单的库函数使用方法场景应用&#xff1a;pdfrw在实际工作中的应用常见问题与解决方案总结 探索PDF的奥秘&#xff1a;p…

Linux平台屏幕|摄像头采集并实现RTMP推送两种技术方案探究

技术背景 随着国产化操作系统的推进&#xff0c;市场对国产化操作系统下的生态构建&#xff0c;需求越来越迫切&#xff0c;特别是音视频这块&#xff0c;今天我们讨论的是如何在linux平台实现屏幕|摄像头采集&#xff0c;并推送至RTMP服务。 我们知道&#xff0c;Linux平台&…

C语言程序设计 笔记代码梳理 重制版

前言 第1章 C语言的流程 1.C程序经历的六个阶段 编辑(Edit)预处理(Preprocess)编译(Compile)汇编(Assemble)链接(Link)执行(Execute) 2.C语言编写代码到运行 都是先编译&#xff0c;后链接&#xff0c;最后运行。&#xff08;.c ---> .obj --->.exe&#xff09;这个过…

RockyLinux8.9上yum安装redis6

我百思不得其解的一个问题 我想在RockyLinux8.9上安装redis6&#xff0c;通过yum list | grep redis看到的redis版本只有redis5 appstream-official仓库是我新加的&#xff0c;这里先不管 于是我通过浏览器访问appstream仓库https://dl.rockylinux.org/vault/rocky/8.9/AppSt…

【个人笔记】VCS工具与命令

Title&#xff1a;VCS工具学习 一 介绍 是什么&#xff1f; VCS (Verilog Compiler Simulator) 是synopsys的verilog 仿真软件&#xff0c;竞品有Mentor公司的Modelsim、Cadence公司的NC-Verilog、Verilog—XL. VCS能够 分析、编译 HDL的design code&#xff0c;同时内置了 仿…

基于yolov8的西红柿检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的西红柿检测系统是一种利用深度学习技术的创新应用&#xff0c;旨在通过自动化和智能化手段提高西红柿成熟度检测的准确性和效率。该系统采用YOLOv8算法&#xff0c;该算法是深度学习领域中的先进目标检测模型&#xff0c;具备实时检测和多目标识别的…

HCIA--实验五:静态路由综合实验

静态路由综合实验 一、实验内容&#xff1a; 1.需求/目的&#xff1a; 在ensp模拟器中使用四个路由器&#xff0c;并且在路由器上创建loopback接口&#xff0c;相当于连接了一台主机&#xff0c;通过配置静态路由的方式实现全网通。 二、实验过程 1.道具&#xff1a; 4个…

ubuntu16.04下qt5.7.1添加对openssl的支持

文章目录 前言一、编译安装openssl二、编译qt5.7.1三、配置qtcreator开发环境四、demo 前言 最近工作中要求客户端和服务端通过ssl加密通信,其中客户端是qt编程,服务端是linux编程.我的开发环境是ubuntu16.04;运行环境是debian9.13,是基于gnu的linux操作系统,64位arm架构. 一…

Android 15 正式发布到 AOSP ,来了解下新特性和适配需求

其实在年初的时候就整理过《2024 &#xff0c;Android 15 预览版来了》 和《提前窥探 Android 15 的新功能与适配》的相关内容&#xff0c;而随着时间进度推进&#xff0c;近日谷歌也正式发布了 Android 15 的正式版&#xff0c;虽然没什么「大亮点」&#xff0c;但是作为开发者…

STM32

&#xff08;以下操作环境为Keil5和proteus8.9&#xff09; 八种输入输出模式及他们的工作模式 分析如下 总线&#xff1a;总线提供了数据在不同组件&#xff08;如处理器、内存、输入输出设备等&#xff09;之间传输的路径&#xff0c;使数据能够快速、准确地在系统内流动。 …

【卡码网C++基础课 18.开房门】

目录 题目描述与分析一、map的基本介绍二、map的使用三、代码编写四、范围for循环 题目描述与分析 题目描述&#xff1a; 假设你手里有一串钥匙&#xff0c;这串钥匙上每把钥匙都有一个编号&#xff0c;对应着一个房门的编号。现给你一个房门编号&#xff0c;你需要判断是否能…

mesh lab导入顶点

文章目录 ubuntu上暗转meshlab导入纯三维点 ubuntu上暗转meshlab 方式一&#xff1a; sudo apt-get install meshlab方式二&#xff1a; unbuntu 上自带的软件商店的ubuntu software里面搜索mesh lab安装即可 导入纯三维点 顶点坐标&#xff1a; -0.409576 0 -0.286788 169…

OpenCV结构分析与形状描述符(7)计算轮廓的面积的函数contourArea()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算轮廓的面积。 该函数计算轮廓的面积。与 moments 类似&#xff0c;面积是使用格林公式计算的。因此&#xff0c;返回的面积与你使用 drawCo…

C语言程序设计(算法的概念及其表示)

一、算法的概念 一个程序应包括两个方面的内容: 对数据的描述:数据结构 对操作的描述:算法 著名计算机科学家沃思提出一个公式: 数据结构 +算法 =程序 完整的程序设计应该是: 数据结构+算法+程序设计方法+语言工具 广义地说,为解决一个问题而采取的方法和步骤…