特殊类的设计
目录
- 一、设计一个类,不能被拷贝
- 二、设计一个类,只能在堆上创建对象
- 三、设计一个类,只能从栈上创建对象
- 四、设计一个类,不能被继承
- 五、设计一个类,只能创建一个对象(单例模式)
- 5.1 饿汉模式
- 5.2 懒汉模式
一、设计一个类,不能被拷贝
//1、请设计一个类,不能被拷贝
//
// 拷贝一个类,要么调用拷贝构造函数,要么调用赋值重载函数,所以要令一个类不能
// 被拷贝,只需要让该类不能调用拷贝构造和赋值重载函数就可以了。
//
// 在C++98语法下,只需要把该类的拷贝构造函数和赋值重载函数声明为私有,
// 并且不定义即可
//
//原因:拷贝构造函数和赋值重载函数只要我们声明了,编译器就不会再默认生成,但是
//我们又不定义它,所以这两个函数就不能被调用,如果定义了,反而在类内部会被调用
// 拷贝构造函数和赋值重载函数,不符合题意;并且我们声明为私有函数,别人想要
//从类外面自己定义也是做不到的,所以这样的类是不能被拷贝的class A
{
public:
private:A(const A& a);A& operator=(const A& a);
};// C++11语法下:
//
// C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上 = delete,
// 表示让编译器删除掉该默认成员函数。
// 所以直接用关键字delete把拷贝构造函数和赋值重载函数删除掉即可
class A
{
private:A(const A& a) = delete;A& operator=(const A& a) = delete;
};
二、设计一个类,只能在堆上创建对象
//2、请设计一个类,只能在堆上创建对象
//
//方法一:要想设计一个类只能在堆上创建对象,只需要将析构函数私有即可//原因:因为只要定义出对象的,对象是自定义类型,必然需要调用构造
// 函数和析构函数,而现在把析构函数私有,则定义的对象在销毁的时候
// 无法调用析构函数,就一定会报错
//但是如果是在堆上创建对象,返回值是一个对象的指针,指针是内置类型,
//不会调用构造函数和析构函数,所以即使析构函数是私有的,也可以通过
//new在堆上创建对象
class HeapOnly
{
public:void func(){cout << "func" << endl;}void Destroy(){//这里delete掉this指针等于是释放了调用//该函数的类的指针,这种写法是正确的delete this;cout << "~HeapOnly()" << endl;}private://析构函数私有~HeapOnly(){}private:int _b;
};//方法二:把构造函数私有,然后提供一个CreateObj的函数,
// 这个函数内部用new创建一个对象,然后返回对象的指针即可,
// 但是要注意把拷贝构造和赋值重载函数delete掉,防止别人
// 在栈上构造对象
//
class HeapOnly
{
public:static HeapOnly* CreateObj(){HeapOnly* ptr = new HeapOnly;return ptr;}
private:HeapOnly(){}HeapOnly(const HeapOnly& ho) = delete;HeapOnly& operator=(const HeapOnly& ho) = delete;
};int main()
{//static B b;HeapOnly* pb = new HeapOnly;pb->func();//HeapOnly b(*pb);pb->Destroy();return 0;
}//int main()
//{
// HeapOnly* ho = HeapOnly::CreateObj();
//
// return 0;
//}
三、设计一个类,只能从栈上创建对象
//3、请设计一个类,只能在栈上创建对象
//不能完全设计出只在栈上创建对象的类;
//沿用2的设计思路,把构造函数私有,然后提供一个CreateObj的函数,
//该函数返回一个在栈上创建的对象。
//因为这个返回的是临时对象,所以不能把拷贝构造函数和赋值函数delete掉,
//因为传值返回对象需要被拷贝。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}void func(){cout << "StackOnly()" << endl;}private:StackOnly(){}// 对一个类实现专属operator new,这句代码的意思是把用new//创建该类对象的方法delete掉,外部不能再利用new来创建对象了void* operator new(size_t size) = delete;};int main()
{StackOnly so = StackOnly::CreateObj();cout << &so << endl;int a = 0;cout << &a << endl;so.func();//因为用户可能用new调用拷贝构造函数在堆上创建对象,所以需要// 把类的专属的operator new给delete掉,禁止用new在堆上创建对象//StackOnly* pso = new StackOnly(so);//这个类唯一不能禁止的就是在静态区创建对象,因为要在栈上创建对象就//一定要有拷贝构造函数,有拷贝构造函数就可以在静态区创建静态对象static StackOnly so1= StackOnly::CreateObj();static int b = 0;cout << &so1 << endl;cout << &b << endl;return 0;
}
四、设计一个类,不能被继承
//4. 请设计一个类,不能被继承
//
//C++98语法
//构造函数私有,然后提供一个CreateObj函数创建对象
// 原因:构造函数私有,也就意味着构造函数不能被显式地调用,
// 因为在继承体系中,子类成员中父类的成员必须调用父类的构造函数
// 初始化父类那一部分成员的,所以如果把父类的构造函数私有,子类
// 就没有办法调用父类的构造函数初始化父类那一部分成员,所以就继承不了
//
class Final
{
public:
private:Final(int f):_f(f){}int _f = 0;
};class A:public Final
{
public://A的构造函数无法调用Final的构造函数,所以Final类不能被继承A():Final(2),_a(1){}private:int _a;
};
//C++11语法:
//C++11提供了一个关键字final,即直接在类后面加上final表示该类不能被继承
class Final final
{
public:Final(int f):_f(f){}private:int _f = 10;
};这里就会报错了,因为Final是不可被继承的
//class F :public Final
//{
//
//};
五、设计一个类,只能创建一个对象(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大楼的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置
信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
5.1 饿汉模式
//1、饿汉模式:一开始(main函数之前)就创建单例对象
//优点:简单
//缺点:
// (1) 如果单例对象要初始化的内容很多,启动速度慢。
// (2) 如果A单例对象的创建依赖B单例对象,要求B对象先创建好,但是我们无法保证先让B单例对象创建好。
// (3) 如果单例对象很大,占用资源很多,但是单例对象创建出来之后不是立刻使用,
// 会占用着大量的内存,导致其它需要内存的地方获取不到内存。
namespace hungry
{class Singalton{public:static Singalton& GetInstance(){return _Inst;}private://构造函数私有,防止别人随意创建对象Singalton(){}//把拷贝构造函数和赋值重载函数删除掉,防止拷贝Singalton(const Singalton& sg) = delete;Singalton& operator=(const Singalton& sg) = delete;//因为全局只有唯一的一个对象,如何保证我们每次获取到的都是同一个对象呢?// 因为静态的全局变量在main函数之前就会定义好的,所以静态的全局变量是全局唯一的。// 所以这里一般都是在类里面声明一个静态的Singalton对象(类外定义),// 在Singalton类里面可以声明Singalton的静态对象吗?// 声明静态对象static Singalton是可以的,// 但是声明普通对象Singalton就不行,为什么呢?// 因为声明普通对象的话就会出现无限套娃的情况了,对象里面又会套一个对象;但// 是声明静态的Singalton对象为什么就可以了呢?// 因为静态的Singalton对象本身并不存在于Singalton类的空间里面,而是存在于// 静态区中,属于所有对象共有的,所以不存在套娃的情况的,所以可以声明静态的Singalton对象的。// // 同时要注意,这里只是声明,普通静态对象必须在类外面定义,但是const static对象比较特殊,// 可以在类内定义这样每一次调用GetInstance的时候就返回这个静态的对象就可以保证每次返回的都是// 同一个_Inst了static Singalton _Inst;// 在C++中,允许在类内部声明一个本类的静态对象的原因是为了方便和灵活性,//当声明一个类的静态成员时,编译器只需要知道该成员的类型和名称,而不需要//知道成员的具体定义和大小。这样做的好处是可以避免一些循环依赖的问题。如// 果不允许在类内部声明本类的静态对象,那么在类定义之前就无法实例化包含静// 态成员的对象,因为在类定义之前,编译器还不知道该类的完整定义。//通过在类内部声明本类的静态对象,可以为程序提供更高的灵活性。在类定义之后// 的任何位置,都可以在需要的时候进行定义和初始化这个静态对象。这样,程序员// 可以根据需要更具灵活性地控制对象的创建和使用。//需要注意的是,在定义之前使用这个静态对象可能会导致未定义的行为,因此在类// 定义之后的某个地方,一定要进行静态对象的定义和初始化,以确保它的正确使用。};//定义,在main函数之前就已经创建好了单例对象Singalton Singalton::_Inst;
}int main()
{//每次调用GetInstance获取到的对象都是同一个cout << &hungry::Singalton::GetInstance() << endl;cout << &hungry::Singalton::GetInstance() << endl;cout << &hungry::Singalton::GetInstance() << endl;return 0;
}
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源(例如锁)竞争,提高响应速度更好。
5.2 懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件, 初始化网络连接,读取文件等等操作时,并且有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
//2、懒汉模式
//比较懒,到有人定义对象的时候才创建对象
//(1) 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
//(2) 缺点:复杂。
namespace lazy
{class Singalton{public:static Singalton* GetInstance(){//这里要使用双判断加锁的方式处理,这样才能很好地提高效率//这个if是判断第一次调用实例对象时需要先创建对象if (_pInst == nullptr){//加锁避免线程安全的问题,两个线程同时进入了这里,需要先竞争锁_pmtx->lock();//这个if是判断如果两个进程同时来到了这里,竞争到锁的进程//先来到这个判断条件,如果_pInst还是nullptr,说明这是第一次调用实例对象//此时创建一个Singalton,后竞争到锁的进程在再一次if判断时_pInst就不再是nullptr//了,此时说明单例对象已经存在了,就不会再创建了if (_pInst == nullptr){_pInst = new Singalton;}_pmtx->unlock();}return _pInst;}//一般情况下,单例对象不需要释放,因为程序正常结束就释放了,// 并且单例对象一般也不大,所以可以把析构函数设置成私有//// 但是有些特殊场景:// 1、中途需要显式释放;//2、程序结束时需要做一些持久化(把数据写入到文件中);// 所以需要提供一个显式调用的DelInstance函数(里面封装析构函数)static void DelInstance(){cout << "DelInstance()" << endl;if (_pInst != nullptr){//自定义对象,调用_pInst对象的析构函数delete _pInst;delete _pmtx;}}void Add(const pair<string, string>& val){_um.insert(val);}private://构造函数Singalton(){}//析构函数~Singalton(){//显式调用析构函数书写日志或者持久化(数据写入文件)cout << "~Singalton()" << endl;FILE* fp = fopen("test.txt", "w");for (const auto& e : _um){fputs(e.first.c_str(), fp);fputs(":", fp);fputs(e.second.c_str(), fp);fputs("\n", fp);}}//拷贝构造函数,单例模式防拷贝Singalton(const Singalton& sg) = delete;//赋值重载函数Singalton& operator=(const Singalton& sg) = delete;//相当于一个垃圾回收类class GC{public://用Gc的析构函数管理单例类的析构函数,因为在Singalton中声明了一个Gc的静态的//成员变量,所以在进程结束的时候会调用析构函数,而Gc析构函数又管理着Singalton的// 析构函数DelInstance,所以无论如何进程结束的时候都会自动调用Singalton的析构// 函数的,所以就不存在内存泄漏的隐患了//~GC(){DelInstance();}};private://如何保证每次调用GetInstance函数的时候获取到的_Inst都是同一个呢?因为这里是运行时//才创建对象的,所以不能用静态的对象,而这里要获取到同一个对象,所以只能在堆上开辟;//但是这里为什么是用静态的呢?因为GetInstance是静态的,没有this指针,但是GetInstance//函数中需要用到_Inst,所以需要这个_Inst也要设置为静态的,这样GetInstance函数才能访问_Inst//同理_mtx也要是静态的static Singalton* _pInst;static mutex* _pmtx;unordered_map<string, string> _um;//在单例类中声明一个Gc类型的静态的成员变量,在类外定义;该对象在进入main函数前就已经创建好了,//到进程结束时才调用析构函数销毁,说明这个变量是整个进程都有效的static GC gc;};//必须在类外定义类内的静态成员变量Singalton* Singalton::_pInst = nullptr;mutex* Singalton::_pmtx = new mutex;Singalton::GC Singalton::gc;
}//GC也可以这样写,这样写更容易理解,用GC创建一个全局对象,进程结束时GC调用析构函数,
// 进而调用lazy::Singalton::DelInstance()释放单例对象,但是遇到多个单例类就把它们
// 全部放到~GC函数中即可,上面那种写法就是把GC定义到单例类内部,每一个GC对象管理一个单例类
//class GC
//{
//public:
// ~GC()
// {
// lazy::Singalton::DelInstance();
// }
//};
//GC gc;int main()
{//lazy::Singalton* p1 = lazy::Singalton::GetInstance();//lazy::Singalton* p2 = lazy::Singalton::GetInstance();//lazy::Singalton* p3 = lazy::Singalton::GetInstance();//cout << p1 << endl;//cout << p2 << endl;//cout << p3 << endl;lazy::Singalton* p1 = lazy::Singalton::GetInstance();p1->Add(make_pair("string", "字符串"));p1->Add(make_pair("left", "左边"));p1->Add(make_pair("right", "右边"));return 0;
}
以上就是常见的特殊类的设计,你学会了吗?今天的分享就到这里啦,如果你感觉到有所收获,那么就点点小心心点点关注呗,后期还会持续更新C++的相关知识哦,我们下期见!!!
相关文章:

特殊类的设计
目录 一、设计一个类,不能被拷贝二、设计一个类,只能在堆上创建对象三、设计一个类,只能从栈上创建对象四、设计一个类,不能被继承五、设计一个类,只能创建一个对象(单例模式)5.1 饿汉模式5.2 懒…...

HTTP 协议的基本格式(部分)
要想了解HTTP,得先知道什么是HTTP,那么HTTP是什么呢?HTTP (全称为 "超文本传输协议") 是一种应用非常广泛的 应用层协议。那什么是超文本呢?那就是除了文本,还有图片,声音,视频等。 …...

Android 第三方app https 抓包
工具选择 Charles 或 Fiddler 都可以 在PC上安装工具并进行设置 Charles Fiddler 设置按官网说明设置一下好。 Charles设置 Fiddler设置 Android Api Level > 24 SSL特殊设置 当Android 的 Api Level > 24时需要修改一下app的一起配置 1.在项目中添加 Android/src/…...

Linux-gitlab常用命令
gitlab常用命令 1、查看gitlab状态2、gitlab启动3、gitlab关闭 1、查看gitlab状态 gitlab-ctl status2、gitlab启动 gitlab-ctl start3、gitlab关闭 gitlab-ctl stop...

android 13.0 Settings主页动态显示和隐藏设置项(一级菜单显示和隐藏)
1.前言 在13.0定制化开发Settings时,有产品需求要求对主页设置项需要动态控制显示和隐藏,这就需要用定义两个页面来区分加载不同settings页面 接下来分析下相关的实现流程 实现思路: 1.用系统变量控制显示和隐藏某些项 2.增加一个自定义页面来适配不同页面 2.Settings主页动态…...

Android MJPEG播放器
MJPEG Android MJPEG播放 支持http mjpeg直播流播放; 支持编码MP4保存视频; 资源 名字资源jar下载GitHub查看Gitee查看 Maven 1.build.grade allprojects {repositories {...maven { url https://jitpack.io }} }2./app/build.grade dependencies {implementation com.g…...

Ubuntu - 安装 MySQL 8
以下是在 Ubuntu 上安装 MySQL 8 的完整步骤: 步骤 1:更新包列表 首先,打开终端并执行以下命令来确保包列表是最新的: sudo apt update 步骤 2:安装 MySQL 8 服务器 接下来,使用以下命令安装 MySQL 8 …...

谷歌浏览器跨域及--disable-web-security无效解决办法
谷歌浏览器跨域设置 (1)创建一个目录,例如我在C盘创建MyChromeDevUserData文件夹 (2) 在桌面选择谷歌浏览器右键 -> 属性 -> 快捷方式 -> 目标,添加--disable-web-security --user-data-dirC:\M…...

IT售前“楠“知识之这!就是售前-尚文网络xUP楠哥
进Q群11372462领取专属报名福利 !!! # 何为售前工程师 售前工程师在一个IT信息化团队中起到了呈上启下的绝对重要作用!站在销售团队的视角,需要售前工程师从技术维度支持销售业务的开展;站在对立面用户的…...

JS元编程
如果说常规编程是写代码去操作数据,那么元编程就是写代码去操作其他代码。 1 属性的特性 JS的属性有名字和值,但每个属性也有3个关联的特性: 可写(writable)特性指定是否可修改属性的值。 可枚举(enume…...

通过Gunicorn、Supervisor和Nginx更好地运行Django
文章目录 通过runserver运行Django通过Gunicorn运行Django通过Nginx来做反向代理通过Supervisor来托管gunicorn和nginx 同步发布在个人站点:https://panzhixiang.cn 通过runserver运行Django 相信用过Django做开发的人对于python manage.py runserver 这个命令一定…...

[SQL] union all
UNION ALL 是一个用于合并多个查询结果集的操作符。它将多个 SELECT 查询的结果合并成一个结果集,并且保留所有的行,包括重复的行。 具体语法如下: SELECT column1, column2, ... FROM table1 UNION ALL SELECT column1, column2, ... FROM…...

Filebeat+Kafka+ELK日志分析架构
目录 一、zookeeper: 1. zookeeper 定义: 2. Zookeeper 工作机制: 3. Zookeeper 特点: 4. Zookeeper 数据结构: 5. Zookeeper 应用场景: 5.1 统一命名服务: 5.2 统一配置管理: 5.3 统一集群管理: 5.4 服务器动态上下线: 5.5 软负载均衡: 6. Zookeeper 选…...

RK3568驱动指南|第六篇-平台总线-第55章 初识设备树
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...

【ELK 使用指南 1】ELK + Filebeat 分布式日志管理平台部署
ELK和EFLK 一、前言1.1 日志分析的作用1.2 需要收集的日志1.3 完整日志系统的基本特征 二、ELK概述2.1 ELK简介2.2 为什么要用ELK?2.3 ELK的组件 三、ELK组件详解3.1 Logstash3.1.1 简介3.1.2 Logstash命令常用选项3.1.3 Logstash 的输入和输出流3.1.4 Logstash配置文件 3.2 E…...

Springboot高频应用注解
本文旨在记录开发中遇到的SpringBoot高频注解,并针对其具体应用记录。 一、LOMBOK相关注解 Slf4j 目的在于使用Log的日志功能,可以在JAVA中自动生成日志记录器!使用时在类上添加Slf4j注解后即可以在类中调用log方法如 可以 调用 log.info …...

面试总结分享:25道数据库测试题
1)什么是数据库测试? 数据库测试也称为后端测试。数据库测试分为四个不同的类别。数据完整性测试 数据有效性测试 数据库相关的性能 测试功能,程序和触发器 2)在数据库测试中,我们需要正常检查什么? 通常&a…...

和硕首次参加展OCP 峰会,将发布多项AI合作项目产品 | 百能云芯
电子代工大厂和硕联合科技宣布,将参与今年的 OCP 全球峰会 (OCP Global Summit),展示与英伟达 (NVIDIA) 合作成果,包含使用英伟达 GH200 Grace Hopper 超级芯片的 MGX AI 服务器,以及搭载 A100、L40 等服务器产品。 OCP 峰会于 10…...

FPGA基于1G/2.5G Ethernet PCS/PMA or SGMII实现 UDP 网络视频传输,提供工程和QT上位机源码加技术支持
目录 1、前言版本更新说明免责声明 2、我这里已有的以太网方案3、设计思路框架视频源选择OV5640摄像头配置及采集动态彩条UDP协议栈UDP视频数据组包UDP协议栈数据发送UDP协议栈数据缓冲IP地址、端口号的修改Tri Mode Ethernet MAC1G/2.5G Ethernet PCS/PMA or SGMIIQT上位机和源…...

小程序setData动态传递key
有些时候可能需要根据key是个变量 比如 let keyName "name" this.setData({keyName :"张三" })本来想将keyName替换为name的,但是小程序只会在data中定义一个key为keyName ,value为“张三”的一条数据。 正确写法为: let keyNam…...

boost Geometry
boost::Geometry boost作为C中最常用的第三方库,Geometry库里面拥有大量的开源算法。 函数作用get获取几何图形(通常为点)的坐标值get (with index)获取框或段的坐标值set设置几何图形(通常为点)的坐标值set (with i…...

凉鞋的 Unity 笔记 201. 第三轮循环:引入变量
201. 第三轮循环:引入变量 在这一篇,我们进行第三轮 编辑-测试 循环。 在之前我们编写了 输出 Hello Unity 的脚本,如下: using System.Collections; using System.Collections.Generic; using UnityEngine;public class FirstGameObject …...

小魔推短视频裂变工具,如何帮助实体行业降本增效?
在如今的互联网时代,大多数的实体老板都在寻找不同的宣传方法来吸引客户,现在短视频平台已经成为重中之重的获客渠道之一,而如何在这个日活用户超7亿的平台获取客户,让更多人知道自己的门店、自己的品牌,泽成为了不少老…...

VBA技术资料MF71:查找所有空格并替换为固定字符
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。我的教程一共九套,分为初级、中级、高级三大部分。是对VBA的系统讲解,从简单的入门,到…...

c++小知识
内联函数 inline 用来替换宏函数 不能分文件编辑 在c语言中#define NULL 0在c中使用nullptr表示空指针class内存的大小计算规则使用的是内存对齐 没有成员,但是还有1个字节,我们使用这个来标记他是个类 类成员函数不存在于类中 为什么每个对象使用的…...

C#上位机序列9: 批量读写+事件广播
1. 读取配置文件及创建变量信息(点位名称,地址,数据类型(bool/short/int/float/long/double)) 2. 读任务&写任务,数据有变化时事件广播通知 using HslCommunication; using HslCommunication.Core; usi…...

ARM +FPGA GPIB IP核实现
目前在数据发生其技术上居领先的是美国的 Tektronix 公司和 Agilent 公司。 Agilent 公司的台式脉冲 / 数据发生器家族的最高时钟频率达 3GHz (定 时发生器),数据发生器 E81200 在通道数为 8CH 时数据速率为 660Mb/s, 即可以产…...

有消息称苹果Vision Pro会有廉价版
据外媒爆料,苹果公司苹果正在研发的头显产品Vision Pro,将会有廉价版。据透露,这款产品预计售价在1500美元至2500美元之间,虽然仍不算低,但较现有的Vision Pro 3499美元的起售价,还是有明显降低。 透露廉价…...

jenkins整合gerrit
背景 公司项目之前使用jenkins整合了gitlab,后面代码迁移到gerrit,所以需要修改jenkins配置。下面就简单的介绍一下jenkins如何整合gerrit。 环境 服务器:linux 环境:docker、jenkins 代码仓库:gerrit 前提 docke…...

PMP考完后应该考什么?
PMP(项目管理专业)认证是全球范围内最受认可和尊重的项目管理资格证书之一。通过PMP考试的人已经展示了他们在项目管理领域的知识和技能。然而,项目管理是一个不断发展和变化的领域,持续学习和进一步提升自己的能力是非常重要的。…...