(P57)面向对象版表达式计算器:单例模式与auto_ptr

2024-06-08 05:58

本文主要是介绍(P57)面向对象版表达式计算器:单例模式与auto_ptr,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1.auto_ptr在单例模式中的应用

1.auto_ptr在单例模式中的应用

  • eg:P57\01.cpp
#include <iostream>
#include <memory>
using namespace std;//单例模式是保证一个类在一个程序中只有一个对象,一个实例
//实现单例模式的关键点是:对象禁止拷贝(只需将拷贝构造函数与等号运算符声明为私有的,且并提供它的实现,这样的话,编译会报错),此外将
//构造函数声明为私有的,防止外部任意构造对象,所以需要提供一个接口ingleton::GetInstance();让外部得到这样一个对象
//因为无法通过对象调用成员函数,所以只能通过类调用成员函数,所以将GetInstance声明为static,此外,不论调用多少次GetInstance,返回的是同一个对象
//否则一个程序就有多个对象的拷贝
class Singleton
{
public://GetInstance成员函数可以访问Singleton私有的构造函数static Singleton* GetInstance(){if (instacne_ == NULL){instacne_ = new Singleton;//new:创建一个类的实例}return instacne_;}~Singleton(){cout<<"~Singleton ..."<<endl;}
private://禁止拷贝就是将拷贝构造函数,等号运算符声明为私有的,就可以保证不进行拷贝构造,也不能赋值//禁止拷贝1:禁止调用拷贝构造函数//将拷贝构造函数声明为私有的,且不提供她的实现Singleton(const Singleton& other);//禁止拷贝2://将赋值操作声明为私有的,禁止赋值操作Singleton& operator=(const Singleton& other);//将构造函数声明为私有的,在main函数中就不能调用构造函数Singleton(){cout<<"Singleton ..."<<endl;}//解决办法是使用智能指针,当智能指针生命周期结束的时候,会自动调用析构函数,从而释放指针所持有(指向)的资源//所以智能指针能用在单例模式中,对资源进行释放static Singleton* instacne_;//仅仅声明,这是裸指针,用智能指针管理// static shared_ptr<Singleton> instacne_;//当整个程序结束时,静态对象也会被销毁,就会调用这个shared_ptr类的析构函数,析构就会将其持有的指针资源进行释放
};Singleton* Singleton::instacne_;//定义性的说明int main(void)
{//Singleton s1;//Singleton s2;//不论调用几次GetInstance,总是返回同一个对象,同一个实例//如何验证他们是同一个实例?只需查看s1和s2指针所指向的地址是否一致Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();//Singleton s3(*s1);		// 调用拷贝构造函数//s4=s2return 0;
}
  • 测试:new Singleton这个对象未被销毁,析构函数未调用。这个指针static Singleton* instacne_;未被销毁
    在这里插入图片描述

  • eg:P57\01_share_ptr.cpp

#include <iostream>
#include <memory>
using namespace std;//单例模式是保证一个类在一个程序中只有一个对象,一个实例
//实现单例模式的关键点是:对象禁止拷贝(只需将拷贝构造函数与等号运算符声明为私有的,且并提供它的实现,这样的话,编译会报错),此外将
//构造函数声明为私有的,防止外部任意构造对象,所以需要提供一个接口ingleton::GetInstance();让外部得到这样一个对象
//因为无法通过对象调用成员函数,所以只能通过类调用成员函数,所以将GetInstance声明为static,此外,不论调用多少次GetInstance,返回的是同一个对象
//否则一个程序就有多个对象的拷贝
class Singleton
{
public://GetInstance成员函数可以访问Singleton私有的构造函数static Singleton* GetInstance(){// if (instacne_ == NULL)// {// 	instacne_ = new Singleton;//new:创建一个类的实例// }// return instacne_;//get()方法返回原生指针,但没有释放所有权,release()方法会释放所有权if (!instacne_.get())){instacne_ = auto_ptr<Singleton>(new Singleton);//智能指针的所有权转移给了instacne_,instacne_持有了new Singleton所分配的内存资源}return instacne_.get();}~Singleton(){cout<<"~Singleton ..."<<endl;}
private://禁止拷贝就是将拷贝构造函数,等号运算符声明为私有的,就可以保证不进行拷贝构造,也不能赋值//禁止拷贝1:禁止调用拷贝构造函数//将拷贝构造函数声明为私有的,且不提供她的实现Singleton(const Singleton& other);//禁止拷贝2://将赋值操作声明为私有的,禁止赋值操作Singleton& operator=(const Singleton& other);//将构造函数声明为私有的,在main函数中就不能调用构造函数Singleton(){cout<<"Singleton ..."<<endl;}//解决办法是使用智能指针,当智能指针生命周期结束的时候,会自动调用析构函数,从而释放指针所持有(指向)的资源//所以智能指针能用在单例模式中,对资源进行释放// static Singleton* instacne_;//仅仅声明,这是裸指针,用智能指针管理static shared_ptr<Singleton> instacne_;//当整个程序结束时,静态对象也会被销毁,就会调用这个shared_ptr类的析构函数,析构就会将其持有的指针资源进行释放
};// Singleton* Singleton::instacne_;//定义性的说明
shared_ptr<Singleton> Singleton::instacne_;int main(void)
{//Singleton s1;//Singleton s2;//不论调用几次GetInstance,总是返回同一个对象,同一个实例//如何验证他们是同一个实例?只需查看s1和s2指针所指向的地址是否一致Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();//Singleton s3(*s1);		// 调用拷贝构造函数//s4=s2return 0;
}
  • 测试:析构函数调用了,说明new Singleton这块资源就能够自动释放了
    在这里插入图片描述

  • eg:P57\02.cpp

#include <iostream>
#include <memory>
using namespace std;//为什么Noncopyable类是禁止拷贝的?
//(1)【采用】禁止对象拷贝的eg演示
//Noncopyable不能构造对象,因为构造对象没意义,仅仅用来继承
class Noncopyable
{
protected:Noncopyable() {};~Noncopyable() {};
private:Noncopyable(const Noncopyable&);const Noncopyable& operator=(const Noncopyable&);
};//这里继承方式是private的,why?
//这里仅仅是继承它的实现,是继承它的实现,而不是继承它的接口,所以是实现继承,而不是接口继承
class Parent : private Noncopyable
{};//Parent是禁止拷贝的,其子类Child也是禁止拷贝的,因为它也继承了Noncopyable的实现
class Child : public Parent 
{};int main(void)
{Parent p1;Parent p2(p1);//要调用Parent拷贝构造函数,Parent构造函数又调用Noncopyable的拷贝构造函数//基类的私有成员在派生类中是不能被访问的,所以编译会失败,即使能访问,基类也没//给出实现,同样也会出错Child c1;Child c2(c1);return 0;
}
  • 测试:也是禁止拷贝的
    在这里插入图片描述

  • eg:P57\03.cpp

#include <iostream>
#include <memory>
using namespace std;//为什么Noncopyable类是禁止拷贝的?
//(1)【采用】禁止对象拷贝的eg演示
//Noncopyable不能构造对象,因为构造对象没意义,仅仅用来继承
class Noncopyable
{
protected:Noncopyable() {};~Noncopyable() {};
private:Noncopyable(const Noncopyable&);const Noncopyable& operator=(const Noncopyable&);
};//这里继承方式是private的,why?
//这里仅仅是继承它的实现,是继承它的实现,而不是继承它的接口,所以是实现继承,而不是接口继承
class Parent : private Noncopyable
{
public://构造函数会调用基类的构造函数,即使没有写出Parent(): Noncopyable(),也是会自动调用的Parent()//若基类没有默认构造函数,那么在子类的成员函数列表中给出基类构造函数的调用{}//拷贝构造函数会调用基类的拷贝构造函数,但是只有Parent(const Parent& other) : Noncopyable(other)这么去写//才会调用基类的拷贝构造函数的Parent(const Parent& other) : Noncopyable(other){}
};//Parent是禁止拷贝的,其子类Child也是禁止拷贝的,因为它也继承了Noncopyable的实现
class Child : public Parent 
{};int main(void)
{Parent p1;//调用构造函数//调用拷贝构造函数,如果这么写:Parent(const Parent& other){},//Parent中实现了拷贝构造函数,是不会调用基类的拷贝构造函数,那么私有的Noncopyable(const Noncopyable&);这个限制就不生效了Parent p2(p1);//要调用Parent拷贝构造函数,Parent构造函数又调用Noncopyable的拷贝构造函数//基类的私有成员在派生类中是不能被访问的,所以编译会失败,即使能访问,基类也没//给出实现,同样也会出错// Child c1;// Child c2(c1);return 0;
}
  • 测试:
    在这里插入图片描述
  • eg:P57\04.cpp
#include <iostream>
using namespace std;//用宏来实现计算某个变量的大小
//sizeof_v
//&x+1,x变量的地址+1,也就是偏移了1个元素的地址,如果元素是4个字节就偏移4个字节
//&x+1 - &x,地址相减,实际上都是指针类型,两个指针相减得到的是他们之间的偏移量,相隔几个元素
//char*类型的地址相隔几个元素就是相隔几个字节
#define sizeof_v(x) (char*)(&x+1) - (char*)&x//使用宏来计算某个类型的大小
//sizeof_t
//((t*)0+1),t*的指针类型,偏移+1,就是偏移一个元素的t类型,得到地址的值刚好等于t类型的大小,但是得到的值类型还是一个指针
//size_t强制转换为整数
#define sizeof_t(t) (sizeof_t)((t*)0+1)//实现一个对齐的宏
//b必须是2的n次方
/*
eg:ALIGN(3, 16) 
v=3
b=16
写成二进制:
v=0011
b-1=1111,b减完1以后就是全1的
~(b-1)取反就是全0(v+b-1)就是:
v       0011
b-1     1111
=      10010(v+b-1) & ~(b-1)就是:100100000   将后面4位都抹除掉了
=   10000      
10000=16
原理思想:某个数要对齐到16的整数倍,用二进制表示的话,后面就是4个0,0000(用十进制去想,100的十进制后面有2个0)
32的整数倍,后面就是5个0
3对齐到16使用的是向上对齐,3 + 15肯定是超过16,超出的部分抹除掉,对于16而言,就是将低4位都置为0,所以得到的值就是对齐的值ALIGN(0, 16) = 0
ALIGN(16, 16) = 0
100001111
11111
*/
#define ALIGN(v, b)  ((v+b-1) & ~(b-1))//为什么要对齐宏ALIGN?因为内存池可能会使用到
/*
比如要分配3个字节,7个字节,9个字节。内存池中的内存块大小是规则的,规则的不容易产生内存碎片。(不规则的物品放在箱子里面会产生空隙或者内存碎片)
要分配内存就无法得到连续的空间,就会被浪费掉。
内存块可以是4K,16K大小的块,32K大小的块。
如果申请内存<=4K,就对齐到4K,保证申请的内存总是4K
如果是4K<内存<=16K,就对齐到16K
如果是16K<内存<=32K,就对齐到32K
采用分级的机制实现内存池
*/class Empty
{};int main(void)
{Empty e;int n;// cout << sizeof(e)<<endl;// cout<<sizeof(Empty)<<endl;//空类的大小是一个字节cout<<sizeof_v(e)<<endl;cout<<sizeof_v(n)<<endl;cout<<sizeof_t(Empty)<<endl;cout<<sizeof_t(int)<<endl;//3对齐到16的整数倍,应该是16cout<<ALLGN(3,16)<<endl;//应该是32cout<<ALLGN(31,16)<<endl;//应该是0cout<<ALLGN(0,16)<<endl;//应该是8192cout<<ALLGN(4198,4096)<<endl;return 0;
}
  • 测试:
    在这里插入图片描述

这篇关于(P57)面向对象版表达式计算器:单例模式与auto_ptr的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041371

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme