您的位置:首页 > 汽车 > 新车 > 网站建设建站_嘉兴免费自助建站模板_网站seo优化的目的_网络营销的常用方法有哪些

网站建设建站_嘉兴免费自助建站模板_网站seo优化的目的_网络营销的常用方法有哪些

2025/4/23 1:59:33 来源:https://blog.csdn.net/MXZSL/article/details/145712908  浏览:    关键词:网站建设建站_嘉兴免费自助建站模板_网站seo优化的目的_网络营销的常用方法有哪些
网站建设建站_嘉兴免费自助建站模板_网站seo优化的目的_网络营销的常用方法有哪些

目录

1、禁止拷贝

2、只在堆上创建对象

3、只在栈上创建对象

4.不能被继承

5、设计一个类,只能创建一个对象(单例模式)

饿汉模式:

懒汉模式:


1、禁止拷贝

这种特殊类的需求就是不让进行拷贝。

设计的核心就是禁止调用拷贝构造和赋值运算符重载即可。

c++98中就是对这两个只声明不定义,且放在私有里。

(如果没有放私有,用户还是可以在类外进行定义)

(只声明放私有里,用户就不能调用赋值或拷贝,这样的话不管有没有定义,都无法使用)

class pl {
private:pl(const pl& s);pl& operator=(const pl& s);
};

c++11中增加了默认成员函数后加=delete,可以禁止调用该函数

class pl {
public:pl(const pl& s) = delete;pl& operator=(const pl& s) = delete;
};

推荐用c++11的用法

2、只在堆上创建对象

class pl {
public:template<class ...Args>//这个是可变参数模板,可不加,不加的话有多少种构造就要多少种createpl//重点是写一个静态的成员函数,用来在外面调用,函数内部强制new对象即可。static pl* createpl(Args&& ...args){return new pl(args...);}//注意,还要禁掉拷贝和赋值,因为拷贝和赋值的时候,不管里面是浅拷贝还是深拷贝//对象都是开辟在栈上的。pl(const pl& s) = delete;pl& operator=(const pl& s) = delete;
private:pl(int a)//将构造私有化,这样外面的人就不能通过各种各样的方式直接构造对象了{//....}pl() {}
};int main()
{//如果不写静态的话,没有对象就不能调用成员函数,没有成员函数又不能创建对象,所以必须静态pl*s1 = pl::createpl(3);return 0;
}

特殊写法

class pl {
public:pl(int a){//....}pl() {}//封掉析构函数~pl() = delete;private:};int main()
{//这样就可以//pl s1;这样的写法就会报错,因为栈上的对象都会生命周期结束都会自动调用析构函数//而析构函数被禁,就会出问题,所以编译器会直接报错。pl *s1 = new pl();return 0;
}

但这一种不能释放资源

所以下面再改下

class pl {
public:pl(int a){//....}pl() {}void Destory() {delete this;}private://不封了,而是放私有,通过成员函数delete this的方式来调用析构~pl() {cout << 1;}};int main()
{pl *s1 = new pl();s1->Destory();return 0;
}

如果再配合智能指针

class pl {
public:pl(int a){//....}pl() {}void Destory() {delete this;}private://不封了,而是放私有,通过成员函数delete this的方式来调用析构~pl() {cout << 1;}};int main()
{pl *s1 = new pl();//这种情况下必须手动给个删除器,不然默认的删除器是直接delete ptr,但此时的析构是私有的//所以必须通过下面的方式调用对象的成员函数,再通过成员函数间接调用析构函数。shared_ptr<pl>s2(new pl(), [](pl* ptr) {ptr->Destory(); });return 0;
}

3、只在栈上创建对象

class pl {
public:template<class ...Args>static pl createpl(Args&& ...args){return pl(args...);}//注意,这里跟堆的不一样,拷贝构造不能封住,因为传值返回,编译器优化之后也是要经过一次拷贝构造的。//pl(const pl& s) = delete;pl& operator=(const pl& s) = delete;//注意,因为没有封住拷贝构造,所以外面仍然可以通过拷贝的方式构造函数//当然不是pl s2(s1)这种,这种还是在栈上的,防的是这种pl s2=new pl(s1);// 所以重载new即可,默认是调用全局std的new,我们只要重载该类的new,并让这个new禁言掉即可。void* operator new(size_t n) = delete;
private:pl(int a){//....}pl() {}
};int main()
{pl s1 = pl::createpl(3);return 0;
}

4.不能被继承

 第一种,c++98,父类构造私有化

class pl {
public:private://构造私有化即可,因为派生类继承父类的时候,父类私有成员是无法被继承的//(或者说虽然被继承下来了,但是派生类也没法调用,相当于隐藏了)//pl() {}};

第二种,利用c++11特性,final,加了final的类无法被继承

class pl final 
{
public:private:};

5、设计一个类,只能创建一个对象(单例模式)

 设计模式:一套反复使用、多数人知晓、经过分类的、代码设计经验的总结。

目的:代码可重用性、代码易读性、代码可靠性。

让代码编写真的工程化,是软件工程的基石

单例模式:一个类在当前进程中只能创建一个对象,即单例模式,该模式保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如内存池(希望一个进程都只访问这一个内存池)、配置信息(服务器配置信息放在一个文件中,这些配置数据都一个单例对象统一读取,然后服务器进程中其他对象再通过这个单例对象获取这些配置信息)。旨在简化复杂环境下的配置管理。

饿汉模式:

//饿汉:main之前,就创建出对象
class Singleton
{
public://静态成员函数static Singleton* GetInstance() {return &_ps;}void OutPut(){cout << a1 << endl;cout << a2 << endl;cout << str << endl;}void Adds(const string& s){str += s;}//记得封拷贝构造和赋值Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;private://先构造私有化Singleton(int a11=0,int a22=0,const string&s="wdawdad"):a1(a11),a2(a22),str(s){}int a1;int a2;string str;//注意,静态成员,不存在对象中,而是在静态区,//相当于全局,声明在类中,定义在类外,受类域限制。//所以是可以在类里面写个同样类的静态对象的。static Singleton _ps;
};
Singleton Singleton::_ps(3,4,"wwwwwww");
int main()
{//这样就能用静态成员函数,访问静态成员(对象),再调用相应的成员函数Singleton::GetInstance()->OutPut();auto s1 = Singleton::GetInstance();s1->OutPut();s1->Adds("dwadwa");s1->OutPut();return 0;
}

饿汉自动释放,对象是存在静态区的。

饿汉的问题:

1、如果单例数据太多,构造初始化的成本较高,会影响程序的启动速度。

比如有好多个单例,每个单例都有一堆信息要存储。这样的话速度就很慢,导致迟迟进不了

main()函数。在进main()函数前,是单线程进行工作的,只有在进了main()函数之后才是多线程工作,这样的话,如果因为单例加载太慢,导致一直堵在main()之前,那程序的启动速度就会非常慢。

2、多个单例类有初始化启动依赖关系,饿汉无法控制。

对于多个单例类的情况,如果对其中一些对象有初始化顺序的要求,比如a对象要求比b对象先初始化,饿汉无法保证。

懒汉模式:

class Singleton 
{
public://调用对象static Singleton* GetInstance() {//第一次调用才会开辟空间if (_ps == nullptr){_ps = new Singleton;}return _ps;}//释放对象static void DelInstance() {if (_ps){delete _ps;_ps = nullptr;//考虑到可能中途释放了单例对象后,//还要重新有一个单例对象,要把指针重新设为空指针//这样下次调用GetInstance就能重新开辟空间了。//这个空指针,还要考虑到如果重复调用了DelInstance,防止多次释放空间//防止释放空指针}}void OutPut(){cout << a1 << endl;cout << a2 << endl;cout << str << endl;}void Adds(const string& s){str += s;}Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;private:Singleton(int a11=0,int a22=0,const string&s="wdawdad"):a1(a11),a2(a22),str(s){}~Singleton() {cout << "~";//可以做很多事情,比如释放的时候把数据写入某个文件等}int a1;int a2;string str;static Singleton*_ps;//考虑到加入了DelInstance之后,如果不显示调用,因为空间是new出来的,不会自动释放//所以加入下面的内部类class DS {public:~DS() {Singleton::DelInstance();}};//注意,如果是放在内部的话,ds一定得开静态。//因为如果是普通的成员的话,只有单例对象释放的时候才会调用ds的析构//但为了让单例对象释放,我们需要调用ds的析构,这样就死循环了,无法达到目的//所以利用静态成员放在静态区的特性,这样的话,程序结束的时候,静态区的ds也会结束生命周期//从而让ds自动调用析构,使得调用DelInstance()static DS ds;
};
//注意,也可以放在外面,这时候ds开不开静态无所谓。
//因为全局的对象也是放在静态区,所以开不开静态都一样,生命周期
//class DS {
//public:
//	~DS() {
//		Singleton::DelInstance();
//	}
//};
//DS ds;
Singleton* Singleton::_ps = nullptr;
Singleton::DS Singleton::ds;int main()
{Singleton::GetInstance();return 0;
}

注意

这个不是完整的懒汉,完整的懒汉还需要设计到线程安全问题,需要加锁,具体的我后面会统一补充文章。目前涉及到线程安全问题的:shared_ptr,懒汉模式。

对于饿汉模式的缺陷懒汉完美解决了。

懒汉不再是一开始就创建对象。

而是在进入main()函数后,根据需求调用单例的GetInstance函数,只有第一次调用该单例类的GetInstance函数才会开辟空间并赋予该单例对象。类对象本身在未调用GetInstance函数前,单例对象指针保持空指针的状态。这样就算main()前有好多个单例类,但单例对象指针都是空指针,不需要多少时间。

而对于初始化顺序的要求,我们手动控制不同单例类的GetInstance函数调用顺序即可。

释放问题:

一般来说懒汉模式下,单例对象也不需要释放,因为我们需要的就是整个程序进程中一直可以访问这个单例对象。

但特殊情况:某个需求,要提前释放单例对象;要求释放的时候把数据写入文件中等等。

上面就是一种释放的写法,但是不一定是类,也可以弄个全局的智能指针来管理。

下面是更简洁的懒汉

class Singleton
{
public://调用对象static Singleton* GetInstance() {//局部的静态对象只有第一次调用函数的时候才会构造对象。//因此可以做到控制多个单例对象初始化顺序。//且又因为局部的静态对象,生命周期也是全局的,所以也可以做到//不显示调用析构,也可以随着生命周期结束自动调用析构。static Singleton _ps;return &_ps;//这个写法只能在c++11及之后写。因为c++11之前无法保证这里的线程安全。}void OutPut(){cout << a1 << endl;cout << a2 << endl;cout << str << endl;}void Adds(const string& s){str += s;}Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;private:Singleton(int a11=0,int a22=0,const string&s="wdawdad"):a1(a11),a2(a22),str(s){}~Singleton() {cout << "~";//可以做很多事情,比如释放的时候把数据写入某个文件等}int a1;int a2;string str;};int main()
{Singleton::GetInstance();return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com