您的位置:首页 > 房产 > 家装 > 大数据培训总结_南昌电影网站开发_外贸平台app_百度论坛首页官网

大数据培训总结_南昌电影网站开发_外贸平台app_百度论坛首页官网

2024/12/22 2:51:13 来源:https://blog.csdn.net/2301_80163789/article/details/143986916  浏览:    关键词:大数据培训总结_南昌电影网站开发_外贸平台app_百度论坛首页官网
大数据培训总结_南昌电影网站开发_外贸平台app_百度论坛首页官网

C++特殊类设计

在实际应用中,可能需要设计一些特殊的类对象,如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类(单例模式)

1. 不能被拷贝的类

拷贝只会发生在两个场景中:拷贝构造函数和赋值运算符重载。因此,让一个类禁止被拷贝,只需要让其拷贝构造函数和赋值运算符重载不能被调用即可

1.1 c++98做法

c++98通过将拷贝构造函数和赋值运算符重载只声明不定义,并将其访问权限设置为私有实现禁止被拷贝。

class CopyBan
{
private:CopyBan(const CopyBan& cb);CopyBan& operator=(const CopyBan & cb);
};

1.2 现代做法

使用c++11提供的delete关键字“删除”拷贝构造函数和赋值运算符重载。

class CopyBan
{
private:CopyBan(const CopyBan& cb) = delete;CopyBan& operator=(const CopyBan& cb) = delete;
};

2. 只能在堆上创建对象的类

2.1 直接法

要使一个类只能在堆上创建对象,思路是:

  1. 将类的构造函数和拷贝构造函数私有,防止别人调用拷贝在栈上生成对象。
  2. 再提供一个静态成员函数,在该静态成员函数内部完成堆对象的创建。
class HeapOnly
{static HeapOnly* Create()//静态解决“先有函数还是现有对象问题”{return new HeapOnly;}
private:HeapOnly(){}
};

但此不能完全封死在栈上创建对象,如果通过 Create()函数先创建一个堆上的对象,再使用默认拷贝构造拷贝堆上的对象,就能够实现在栈上创建对象。

HeapOnly* ho1 = HeapOnly::Create();
HeapOnly* ho2(ho1);

所以最后还需要封死通过拷贝构造创建栈上对象:

c++98:private:HeapOnly& HeapOnly(const HeapOnly& ho){}

c++11:HeapOnly& HeapOnly(const HeapOnly& ho)=delete;

2.2 私有析构函数法

设计不能被拷贝的类还有一种方法,通过私有化析构函数,让栈上对象无法在离开作用域时自动调用析构函数,因此在栈上的创建对象的代码都不能被编译通过。再设计一个 release()函数手动释放堆上的对象

class HeapOnly
{
public:static HeapOnly* Create(){return new HeapOnly;}void relase(){delete this;}
private:~HeapOnly(){}
};

3. 只能在栈上创建对象的类

要使一个类只能在栈上创建对象,思路是:

  1. 私有化构造函数
  2. 设计静态函数返回对象
class StackOnly
{
public:static StackOnly Create(){return StackOnly();}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;private:StackOnly():_a(0){}int _a;
};

设计只能在栈上创建对象的类还要注意将new和delete删除,避免使用new通过拷贝构造创建堆上对象。且由于 Create()函数被设计成传值返回,不能直接通过删除拷贝构造实现(因为临时对象)。

删除new和delete的原理是,编译器默认生成一个new和一个delete,现将重载new和delete在类中重载,那么类对象会调用重载的new和重载的delete(重载后不再默认生成),但由于重载的new和重载的delete被删除,类对象在创建时便无法使用。

StackOnly so1 = StackOnly::Create();
StackOnly* so2 = new StackOnly(so1);

4. 不能被继承的类

要使一个类不能被继承,方法是:

  1. c++98:基类析构函数私有,派生类不能调用基类的构造函数,无法编译通过
  2. c++11:使用final关键字标记基类,表示该类不能被继承

5. 单例模式

单例模式要求一个类只能创建一个对象,该模式可以抱枕系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

单例模式有两种实现模式:

  1. 饿汉模式

  2. 懒汉模式

5.1 饿汉模式

饿汉形容程序对对象的需要比较紧迫,不管将来用不用,在程序启动时就马上先创建一个唯一的实例对象(一般在main函数之前创建)。

#include<iostream>
using namespace std;class ehan
{
public:static ehan* GetInstance(){return &_e;}int SetInfo(int info){_info = info;return _info;}ehan(const ehan& e) = delete;ehan& operator=(const ehan& e) = delete;
private:ehan(){}int _info;static ehan _e;//声明
};ehan ehan::_e;//定义
int main()
{cout<<ehan::GetInstance()->SetInfo(1);return 0;
}

优先:简单

缺点:可能会导致进程启动慢,且如果有多个单例类使用饿汉模式,它们的对象实例启动顺序不确定

5.2 懒汉模式

懒汉模式可以完美解决饿汉模式的缺点,懒汉模式一般在第一次调用 GetInstance() 的时候创建单例对象。

#include<iostream>
using namespace std;class lanhan
{
public:static lanhan* GetInstance(){static lanhan _lh;return &_lh;}int SetInfo(int info){_info = info;return _info;}lanhan(const lanhan& e) = delete;lanhan& operator=(const lanhan& e) = delete;
private:lanhan(){}int _info;
};int main()
{cout<<lanhan::GetInstance()->SetInfo(1);return 0;
}

这里在 GetInstance()里 定义了一个局部静态对象 static lanhan _lh; ,即使调用多次 GetInstance(),这个创建对象的代码也只会执行一次,但这种使用方法是c++11之后支持,且有线程安全风险

传统且线程安全方法:

#include<iostream>
#include<mutex>
using namespace std;class lanhan
{
public:static lanhan* GetInstance(){if (_lh == nullptr)//双重检查保证线程安全{unique_lock<mutex> lock(_mtx);if (_lh == nullptr){_lh = new lanhan;}}return _lh;}int SetInfo(int info){_info = info;return _info;}lanhan(const lanhan& e) = delete;lanhan& operator=(const lanhan& e) = delete;
private:lanhan(){}int _info;static mutex _mtx;static lanhan* _lh;};
lanhan* lanhan::_lh = nullptr;
mutex lanhan::_mtx;int main()
{cout<<lanhan::GetInstance()->SetInfo(1);return 0;
}

版权声明:

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

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