网站描述在哪里写,wordpress 试用,wordpress仪表盘文件目录,网站建设常用软件C特殊类设计
在实际应用中#xff0c;可能需要设计一些特殊的类对象#xff0c;如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类#xff08;单例模式#xff09;。
1. 不能被拷贝的类
拷贝只会发生在两个场景…C特殊类设计
在实际应用中可能需要设计一些特殊的类对象如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类单例模式。
1. 不能被拷贝的类
拷贝只会发生在两个场景中拷贝构造函数和赋值运算符重载。因此让一个类禁止被拷贝只需要让其拷贝构造函数和赋值运算符重载不能被调用即可。
1.1 c98做法
c98通过将拷贝构造函数和赋值运算符重载只声明不定义并将其访问权限设置为私有实现禁止被拷贝。
class CopyBan
{
private:CopyBan(const CopyBan cb);CopyBan operator(const CopyBan cb);
};1.2 现代做法
使用c11提供的delete关键字“删除”拷贝构造函数和赋值运算符重载。
class CopyBan
{
private:CopyBan(const CopyBan cb) delete;CopyBan operator(const CopyBan cb) delete;
};2. 只能在堆上创建对象的类
2.1 直接法
要使一个类只能在堆上创建对象思路是 将类的构造函数和拷贝构造函数私有防止别人调用拷贝在栈上生成对象。再提供一个静态成员函数在该静态成员函数内部完成堆对象的创建。 class HeapOnly
{static HeapOnly* Create()//静态解决“先有函数还是现有对象问题”{return new HeapOnly;}
private:HeapOnly(){}
};
但此不能完全封死在栈上创建对象如果通过 Create()函数先创建一个堆上的对象再使用默认拷贝构造拷贝堆上的对象就能够实现在栈上创建对象。
HeapOnly* ho1 HeapOnly::Create();
HeapOnly* ho2(ho1);所以最后还需要封死通过拷贝构造创建栈上对象 c98private:HeapOnly HeapOnly(const HeapOnly ho){} c11HeapOnly HeapOnly(const HeapOnly ho)delete; 2.2 私有析构函数法
设计不能被拷贝的类还有一种方法通过私有化析构函数让栈上对象无法在离开作用域时自动调用析构函数因此在栈上的创建对象的代码都不能被编译通过。再设计一个 release()函数手动释放堆上的对象。
class HeapOnly
{
public:static HeapOnly* Create(){return new HeapOnly;}void relase(){delete this;}
private:~HeapOnly(){}
};3. 只能在栈上创建对象的类
要使一个类只能在栈上创建对象思路是 私有化构造函数设计静态函数返回对象 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. 不能被继承的类
要使一个类不能被继承方法是 c98基类析构函数私有派生类不能调用基类的构造函数无法编译通过c11使用final关键字标记基类表示该类不能被继承 5. 单例模式
单例模式要求一个类只能创建一个对象该模式可以抱枕系统中该类只有一个实例并提供一个访问它的全局访问点该实例被所有程序模块共享。
单例模式有两种实现模式 饿汉模式 懒汉模式
5.1 饿汉模式
饿汉形容程序对对象的需要比较紧迫不管将来用不用在程序启动时就马上先创建一个唯一的实例对象一般在main函数之前创建。
#includeiostream
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()
{coutehan::GetInstance()-SetInfo(1);return 0;
}优先简单 缺点可能会导致进程启动慢且如果有多个单例类使用饿汉模式它们的对象实例启动顺序不确定 5.2 懒汉模式
懒汉模式可以完美解决饿汉模式的缺点懒汉模式一般在第一次调用 GetInstance() 的时候创建单例对象。
#includeiostream
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()
{coutlanhan::GetInstance()-SetInfo(1);return 0;
}这里在 GetInstance()里 定义了一个局部静态对象 static lanhan _lh; 即使调用多次 GetInstance()这个创建对象的代码也只会执行一次但这种使用方法是c11之后支持且有线程安全风险。 传统且线程安全方法
#includeiostream
#includemutex
using namespace std;class lanhan
{
public:static lanhan* GetInstance(){if (_lh nullptr)//双重检查保证线程安全{unique_lockmutex 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()
{coutlanhan::GetInstance()-SetInfo(1);return 0;
}