当前位置: 首页 > news >正文

北京市建筑网站软件开发实例

北京市建筑网站,软件开发实例,什么网站做弹窗广告好,网站营销的特征有目录标题 设计一个不能被拷贝的类设计一个只能从堆上创建对象的类设计一个只能在栈上创建对象的类设计一个无法被继承的类什么是单例模式饿汉模式饿汉模式的缺点懒汉模式懒汉模式的优点懒汉模式的缺点特殊的懒汉 设计一个不能被拷贝的类 拷贝只会放生在两个场景中#xff1a;… 目录标题 设计一个不能被拷贝的类设计一个只能从堆上创建对象的类设计一个只能在栈上创建对象的类设计一个无法被继承的类什么是单例模式饿汉模式饿汉模式的缺点懒汉模式懒汉模式的优点懒汉模式的缺点特殊的懒汉 设计一个不能被拷贝的类 拷贝只会放生在两个场景中拷贝构造函数以及赋值运算符重载因此想要让一个类禁止拷贝只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。那么c98采用的方式就是将拷贝构造函数与赋值运算符重载只声明不定义并且将其访问权限设置为私有即可比如说下面的代码 class CopyBan {// ...private:CopyBan(const CopyBan);CopyBan operator(const CopyBan);//... };设置成私有如果只声明没有设置成private用户自己如果在类外定义了就不能禁止拷贝了只声明不定义是因为该函数根本不会调用定义了其实也没有什么意义不写反而还简单而且如果定义了就不会防止成员函数内部拷贝了。C11扩展delete的用法delete除了释放new申请的资源外如果在默认成员函数后跟上delete表示让编译器删除掉该默认成员函数那么这里的代码就如下 class CopyBan {// ...CopyBan(const CopyBan)delete;CopyBan operator(const CopyBan)delete;//... };设计一个只能从堆上创建对象的类 我们可以在三个位置上创建类的对象分别为堆上栈上和静态区上创建的方式如下 int main() {HeapOnly tmp1;//栈上HeapOnly* tmp2 new HeapOnly;//堆上static HeapOnly tmp3;//静态区上 }创建对象的时候必须得调用构造函数那么这里就可以将构造函数放到私有里面然后创建一个函数通过new来着堆上创建对象但是这里会有一个先有鸡还是先有蛋的问题所以我们把这个创建对象的函数变为静态的比如说下面的代码 class HeapOnly { public:static HeapOnly* CreateObject(){return new HeapOnly;} private:HeapOnly() {} };这样写就可以让该容器智能在堆上创建空间那么上面的代码运行的结果就如下 可以看到上面的代码就出问题原因时无法调用构造函数那么这里要想创建对象就智能调用里面的函数比如说下面的代码 int main() {HeapOnly* tmp HeapOnly::CreateObject(); }虽然上面的写法可以有效的避免在栈上和静态区上创建对象但是它依然可以通过拷贝构造在栈上创建对象所以还得把拷贝构造禁止掉比如说下面的代码 class HeapOnly { public:static HeapOnly* CreateObject(){return new HeapOnly;} private:HeapOnly() {}HeapOnly(const HeapOnly) delete; };这里还有个方法就是将析构函数私有化因为栈上的变量会自动销毁并调用析构函数所以当对象的生命周期结束之后就会自动地调用析构函数来释放空间但是析构函数私有化了所以掉不动也就进一步阻止了对象在栈上船舰但是堆上创建的对象也是掉不了析构函数所以这里可以创建一个函数给堆上的变量能够调用析构函数来释放空间那么这里地代码就如下 #includeiostream using namespace std; class HeapOnly { public:HeapOnly(){}void Destory(){this-~HeapOnly();} private:~HeapOnly(){}HeapOnly(const HeapOnly tmp) delete; }; int main() {HeapOnly* tmp1 new HeapOnly;tmp1-Destory();return 0; }运行地结果也是没有错误的 设计一个只能在栈上创建对象的类 这里也是跟上面的思路差不多创建一个函数函数中栈上创建对象并返回该对象比如说下面的代码 class StackOnly { public:static StackOnly creatobj(){return StackOnly();} private:StackOnly(){} };那么我们就可以用下面的代码在栈上创建对象 {StackOnly tmp1 StackOnly::creatobj();return 0; }如果在其他位置上创建空间的话就会直接报错比如说下面的代码 int main() {StackOnly* tmp1 new StackOnly;static StackOnly tmp2;return 0; }报错的内容如下 但是这种方法没有完全的封死我们依然可以通过拷贝构造在静态区上开辟空间比如说下面的代码 int main() {static StackOnly tmp1 StackOnly::creatobj();return 0; }那能不能把拷贝构造函数也封掉的呢答案使不行的因为拷贝构造函数被封掉之后不仅静态区上无法创建空间而且栈上也没有办法创建对象这里还有种方法就是封掉operator new和operator delete比如说下面的代码 class StackOnly { public:StackOnly(){}void* operator new(size_t size) delete;void operator delete(void* p) delete; private: };那么这个时候再使用new创建对象就会直接报错比如说下面的运行结果 但是这种方法只能保证不能在堆上开辟空间无法保证在静态区上也不能开辟空间比如说下面的代码还是可以正常运行的 int main() {static StackOnly tmp2;return 0; }所以痛过常规方法这里没有办法完全封死的要想完全封死的话就只有一个办法就是封掉拷贝构造函数并且不接受对象通过引用或者创建临时匿名对象来直接调用函数比如说下面的代码 int main() {StackOnly::creatobj().Print();const StackOnly so4 StackOnly::creatobj();so4.Print();return 0; }代码的运行结果如下 但是这样的实现存在一个缺陷就是无法修改对象里面的内容。 设计一个无法被继承的类 方法一就是构造函数私有 C98中构造函数私有化派生类中调不到基类的构造函数所以无法继承 class NonInherit { public:static NonInherit GetInstance(){return NonInherit();} private:NonInherit(){} };方法二就是添加finalfinal修饰类表示该类不能被继承那么这里的代码就如下 class NonInherit final {// .... };什么是单例模式 一个类只能创建一个对象即单例模式该模式可以保证系统中该类只有一个实例并提供一个访问它的全局访问点该实例被所有程序模块共享。比如在某个服务器程序中该服务器的配置信息存放在一个文件中这些配置数据由一个单例对象统一读取然后服务进程中的其他对象再通过这个单例对象获取这些配置信息这种方式简化了在复杂环境下的配置管理单例模式有两种实现方式第一种就是饿汉模式第二种就是懒汉模式我们首先来看看饿汉模式的原理。 饿汉模式 单例模式的特点就是全局只有一个唯一对象如何保证全局只有一个唯一对象呢首先构造函数封死如果构造函数不封起来的话使用者可以用这个类创建多个对象那么我们就可以创建一个类类中含有一个map容器并装着一些数据然后类里面就提供了一些函数用于访问map的数据修改map的数据等等然后把这个类的构造函数放到私有里面比如说下面的代码 class InfoSingleton { public:private:InfoSingleton(){}mapstring, int _info; };然后这里就存在一个问题如何来创建对象并且保证对象的个数就只有一个呢?答案是在类里面创建一个静态的变量然后提供一个静态成员函数来获取对象的引用比如说下面的代码 class InfoSingleton { public:static InfoSingleton GetInstance(){return _sins;} private:InfoSingleton(){}mapstring, int _info;static InfoSingleton _sins; }; InfoSingleton InfoSingleton::_sins;外面的静态成员变量是定义内部的静态成员变量是声明然后为了方便往对象里面的插入数据和修改数据我们还要创建一个insert函数在里面通过方括号来修改内部的数据比如说下面的代码 void insert(string name, int salary) {_info[name] salary; }然后我们就可以在main函数里面通过引用或者匿名调用的方式来插入或者修改数据比如说下面的代码: int main() {InfoSingleton::GetInstance().insert(张三, 10000);InfoSingleton::GetInstance().insert(李四, 12000);InfoSingleton tmp InfoSingleton::GetInstance();tmp.insert(王五, 13000);tmp.insert(老六, 14000);return 0; }然后我们还可以创建一个print函数用来打印内部的数据比如说下面的代码 void print() {for (auto ch : _info){cout ch.first : ch.second endl;} }然后我们就可以查看容器里面的数据那么这里的运行结果如下 这种方式就是饿汉模式一开始就创建对象但是这种方法存在一个问题就是拷贝构造和赋值重载会多创建出来一个对象不符合特征所以这里得把拷贝构造和赋值重载也去掉那么这里的代码就如下 class InfoSingleton { public:static InfoSingleton GetInstance(){return _sins;}void insert(string name, int salary){_info[name] salary;}void print(){for (auto ch : _info){cout ch.first : ch.second endl;}} private:InfoSingleton(){}InfoSingleton(InfoSingleton const) delete;InfoSingleton operator(InfoSingleton const) delete;mapstring, int _info;static InfoSingleton _sins; }; InfoSingleton InfoSingleton::_sins;我们就把这样的实现方式成为饿汉模式因为它在程序的一开始就创建了一个对象。 饿汉模式的缺点 1.饿汉模式初始化时如果数据太多会导致启动的速度较慢因为饿汉模式在main函数之前就得进行初始化而数据的含量可能会非常的多并且数据可能还要链接数据库等等所以可能会导致启动的速度很慢。 2.多个单例类有初始化依赖关系饿汉模式无法控制。比如说A和B都是单利类要求先初始化A再初始化B因为B会依赖A但是饿汉模式中的变量都是全局变量无法保证初始化顺序所以这里就可能会出错那么未来解决这个问题有人就提出了懒汉模式。 懒汉模式 饿汉模式是程序一开始就创建对象而懒汉模式则是先不着急创建对象等需要的时候再创建对象那么我们就把类里面的静态对象修改成为一个静态的指针对象在类外面将其初始化为空在GetInstance函数里面就判断当前的指针是否为空如果为空的话就创建对象最后返回当前的指针指向的对象那么这里的代码就如下 class InfoSingleton { public:static InfoSingleton GetInstance(){//第一次调用的时候创建对象if (_psins nullptr){_psins new InfoSingleton;}return *_psins;}void insert(string name, int salary){_info[name] salary;}void print(){for (auto ch : _info){cout ch.first : ch.second endl;}} private:InfoSingleton(){}InfoSingleton(InfoSingleton const) delete;InfoSingleton operator(InfoSingleton const) delete;mapstring, int _info;static InfoSingleton* _psins; }; InfoSingleton* InfoSingleton::_psinsnullptr;那么这里就不是一开始就创建对象而是等你调用的时候创建对象。 懒汉模式的优点 1.对象在main函数之后才会创建不会影响启动顺序。 2.可以主动控制初始化顺序。比如说A依赖于B那么我们就可以先调用A再调用B来解决这个问题。 懒汉模式的缺点 多个线程一起调用单例对象的时候创建对象时也可能会创建多个对象第一个线程看到的当前类没有对象会new一个第一个线程还没有创建完成第二个线程跑过来发现依然没有所以这个时候就又会创建一个对象出来所以这个时候就得在类里面添加一个枷锁变量因为静态的成员函数没有this指针不能访问非静态的成员变量所以这里就得创建一个静态的枷锁那么这里的代码如下 class InfoSingleton { public:static InfoSingleton GetInstance(){mtx.lock();if (_psins nullptr){_psins new InfoSingleton;}mtx.unlock();return *_psins;}void insert(string name, int salary){}void print(){} private:InfoSingleton(){}InfoSingleton(InfoSingleton const) delete;InfoSingleton operator(InfoSingleton const) delete;mapstring, int _info;static InfoSingleton* _psins;static mutex mtx; }; mutex InfoSingleton::mtx; InfoSingleton* InfoSingleton::_psinsnullptr;可是这里就存在一个问题我们只会在第一次创建对象的时候出现问题而我们每次使用这个函数的时候都得进行枷锁解锁这里是不是就会产生时间消耗啊所以能不能把枷锁放到if的里面呢答案是不行的这里会出现线程安全因为可能会两个线程都进入到创建对象里面并且这种方法会加剧线程安全的风险所以这里就可以添加双层检查来进行枷锁保护那么这里的代码就如下 static InfoSingleton GetInstance() {if (_psins nullptr)//对象new出来了避免每次都枷锁的检查提高性能。{mtx.lock();if (_psins nullptr)//保证线程安全且执行一次{_psins new InfoSingleton;}mtx.unlock();}return *_psins; }但是这里new可能会抛出异常所以这里得捕捉异常如果没捕捉的话这里就不会解锁了那么改进后的代码就如下 static InfoSingleton GetInstance(){if (_psins nullptr){mtx.lock();try{if (_psins nullptr){_psins new InfoSingleton;}}catch (...){mtx.unlock();throw;}}return *_psins;}上面的释放方式有点不好看所以这里我们可以使用智能指针的思想来解决这里的问题创建一个类类中含有一个锁的引用对象那么这个类的构造函数就是对这个锁进行上锁类的析构函数就是对这个类进行解锁那么这里的代码就是这样 templateclass Lock class LockGuard { public:LockGuard(Lock lk):_lk(lk){_lk.lock();}~LockGuard(){_lk.unlock();}private:Lock _lk; };那么上面的函数我们就可以写成下面这样: static InfoSingleton GetInstance() {if (_psins nullptr){LockGuardmutex lock(mtx);if (_psins nullptr){_psins new InfoSingleton;}}return *_psins; }一般单例对象不需要考虑内存释放,因为单例对象一般都是在整个程序里面进行使用但是单例对象在不用时必须得手动处理让一些资源进行报错所以这个时候就得提供一个delete函数来手动释放那么这里的函数代码如下 static void DelInstance() {/*保存数据到文件...*/std::lock_guardmutex lock(mtx);if (_psins){delete _psins;_psins nullptr;} }那这里能不能做到自动释放该类呢答案时可以的我们可以定义一个内部类并且该类的析构函数里面调用DelInstance然后在外部类里面添加一个该类的静态对象这样当单例的那个类被销毁时内部类的对象就会被销毁内部类对象被销毁时就会调用它的析构函数然后析构函数就调用GetInstance函数来释放那么完整的代码就如下 templateclass Lock class LockGuard { public:LockGuard(Lock lk):_lk(lk){_lk.lock();}~LockGuard(){_lk.unlock();}private:Lock _lk; }; class InfoSingleton { public:static InfoSingleton GetInstance(){if (_psins nullptr){LockGuardmutex lock(mtx);if (_psins nullptr){_psins new InfoSingleton;}}return *_psins;}void insert(string name, int salary){_info[name] salary;}void print(){for (auto ch : _info){cout ch.first : ch.second endl;}}static void DelInstance(){/*保存数据到文件...*/std::lock_guardmutex lock(mtx);if (_psins){delete _psins;_psins nullptr;}}class GC{public:~GC(){if (_psins){cout ~GC() endl;DelInstance();}}}; private:InfoSingleton(){}InfoSingleton(InfoSingleton const) delete;InfoSingleton operator(InfoSingleton const) delete;mapstring, int _info;static InfoSingleton* _psins;static mutex mtx;static GC _gc; }; mutex InfoSingleton::mtx; InfoSingleton* InfoSingleton::_psinsnullptr; InfoSingleton::GC InfoSingleton::_gc;特殊的懒汉 class InfoSingleton { public:static InfoSingleton GetInstance(){static InfoSingleton sinst;return sinst;}void Insert(string name, int salary){_info[name] salary;}void Print(){for (auto kv : _info){cout kv.first : kv.second endl;}cout endl;}private:InfoSingleton(){cout InfoSingleton() endl;}InfoSingleton(const InfoSingleton info) delete;InfoSingleton operator(const InfoSingleton info) delete;mapstring, int _info;// ... };我们之前说过函数中的静态成员变量是在第一次调用该函数的时候进行创建并且初始化第一次调用完之后就不会再执行该代码所以上面的代码能够保证只创建一个对象并且该对象的创建也发生了main函数之后可是面对多线程的时候上面的代码可能会出现线程安全问题吗答案是C11之前这里是不能保证sinst的初始化是线程安全的C11之后可以保证安全。所以这种写法不一定安全并不是通用的方法所以对于这种写法如果编译器支持c11则可以写如果不支持则不能写。
http://www.zqtcl.cn/news/646411/

相关文章:

  • 四川省建设厅网站官网自己做的网站能上传到凡科吗
  • 米拓网站建设-app定制开发免费个人建站系统
  • 网站改版公司如何帮公司做网站
  • 曹县汽车网站建设网站怎么做才 吸引人
  • 河南周口东宇网站建设wordpress怎么重新安装插件
  • wordpress无法上传主题南通做网站优化公司
  • 做彩票网站能挣到钱吗南充市房产信息网
  • 沧州北京网站建设金华网站建设哪个公司好点
  • 北京朝阳建站优化wordpress主题访问慢
  • wordpress最快仿站酷炫个人特别网站
  • 公司建站详细步骤如何注册一家公司要多少钱
  • 网站推广网络营销山西大学物理电子工程学院研招网
  • 亚马逊做国际外贸在哪个网站毕业设计网站开发选题依据
  • 镇江网站排名优化费用app软件开发平台游戏
  • 襄阳网站建设xytzg南通网站建设top
  • 有没有做产品团购的网站2d动画制作软件
  • 成都网站排名生客seo杭州专业网站制作设计
  • 阿里云 企业 网站四平市网站建设
  • 政务门户网站建设信息奇人网站
  • 打开网站弹出广告代码如何建设网站方便后期维护
  • 海淀网站建设龙岩做网站用什么cms 知乎
  • 网站托管费用多少免费一卡二卡三
  • 长沙做网站品牌中信建设官网站首页
  • 网站空白页黑链聊城网站建设代理商
  • 微信上打开连接的网站怎么做在网上可以做宣传的有那些网站
  • 公司在选择网站时应考虑什么问题溧阳 招网站开发
  • 兴宁电子商务网站建设农村电子商务网站建设方案
  • 张北县网站建设网站设计师加油站
  • 网站建设车成本网站开发网络结构图
  • 建设部职称网站宝山网站制作