C++:特殊类设计
目录
一.前几个特殊类设计
1.请设计一个类,不能被拷贝
2. 请设计一个类,只能在堆上创建对象
3. 请设计一个类,只能在栈上创建对象
4. 请设计一个类,不能被继承
C++98方式
C++11方法
二.单例模式
5. 请设计一个类,只能创建一个对象(单例模式)
饿汉模式
懒汉模式
一.前几个特殊类设计
1.请设计一个类,不能被拷贝
这种防拷贝需求例如:
unique_ ptr
thread(线程)
mutex (锁)
istream(IO流对象)
ostream
class CopyBan
{
// ...
private:
CopyBan(const CopyBan&);
CopyBan& operator=(const CopyBan&);
//...
};
class CopyBan
{
// ...
CopyBan(const CopyBan&)=delete;
CopyBan& operator=(const CopyBan&)=delete;
//...
};
2. 请设计一个类,只能在堆上创建对象
我们通常创建对象时,对象调用构造函数后创建在这三个区域:
class HeapOnly
{}
HeapOnly h1; 栈
static HeapOnly h2; 静态区
HeapOnly* ph3 = new HeapOnly; 堆区
3.拷贝构造需要防止:Heap0nly copy( *ph4) ; 指针ph4对应的对象虽然在堆上,但是拷贝后copy这个对象在栈上,所以要用delete删除拷贝构造函数。
4.赋值重载可以不禁:拷贝构造是把已构造对象拷贝给一个未构造的对象,赋值是把两个已经构造的函数互相赋值,这里构造只能再堆上,互相赋值仍是在堆上。
3. 请设计一个类,只能在栈上创建对象
这里的拷贝构造依然可以去掉,因为CreateObj()中的 return StackOnly(); 先构造一个匿名对象,再拷贝构造一个临时变量,临时变量再拷贝构造给h1,被编译器优化为一次构造,直接构造h1
class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
//StackOnly st;
//return st;
}
StackOnly(const StackOnly&) = delete;
//void Print()
//{
// cout << "Stack Only" << endl;
//}
private:
// 构造函数私有
StackOnly()
{}
};
int main()
{
StackOnly h1 = StackOnly::CreateObj();
//StackOnly::CreateObj().Print();
//static StackOnly h2;
//StackOnly* ph3 = new StackOnly;
return 0;
}
4. 请设计一个类,不能被继承
C++98方式
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
static NonInherit GetInstance()
{
return NonInherit();
}
private:
NonInherit()
{}
};
C++11方法
class A final
{
....
};
二.单例模式
5. 请设计一个类,只能创建一个对象(单例模式)
饿汉模式
// 适配器模式/单例模式/迭代器模式 扩展学习:观察者模式/工厂模式
// 饿汉 -- 一开始(main函数之前)就创建
class Singleton
{
public:
static Singleton* GetInstance()
{
return _spInst;
}
void Print();
private:
Singleton()
{}
Singleton(const Singleton&) = delete;
//static Singleton _sInst; // 声明
static Singleton* _spInst; // 声明
int _a = 0;
};
//Singleton Singleton::_sInst; // 定义
Singleton* Singleton::_spInst = new Singleton; // 定义
void Singleton::Print()
{
cout << _a << endl;
}
int main()
{
// GetInstance()可以获取到这个Singleton类的单例对象
Singleton::GetInstance()->Print();
//Singleton st1; 无法创建对象
//Singleton* st2 = new Singleton; 无法创建对象
//Singleton copy(*Singleton::GetInstance()); 无法创建对象
return 0;
}
懒汉模式
懒汉—— 一开始不创建对象,第一获取单例对象调用函数GetInstance时再创建对象
和饿汉相比,饿汉:Singleton* Singleton::_spInst = new Singleton; // 定义
懒汉初始化为空指针:Singleton* Singleton::_spInst = nullptr;
想让进程中某个信息只有一份,就可以把例设为单例
// 懒汉 -- 一开始不创建对象,第一调用GetInstance再创建对象
class InfoMgr
{
public:
static InfoMgr* GetInstance()
{
// 还需要加锁,这个后面讲 -- 双检查加锁
if (_spInst == nullptr)
{
_spInst = new InfoMgr;
}
return _spInst;
}
void SetAddress(const string& s)
{
_address = s;
}
string& GetAddress()
{
return _address;
}
// 实现一个内嵌垃圾回收类
class CGarbo {
public:
~CGarbo() {
if (_spInst)
delete _spInst;
}
};
// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
static CGarbo Garbo;
private:
InfoMgr()
{}
~InfoMgr()
{
// 假设析构时需要信息写到文件持久化
}
InfoMgr(const InfoMgr&) = delete;
string _address; ————————————成员数据
int _secretKey;
static InfoMgr* _spInst; // 声明
};
InfoMgr* InfoMgr::_spInst = nullptr; // 定义
InfoMgr::CGarbo Garbo;
int main()
{
// 全局只有一个InfoMgr对象
InfoMgr::GetInstance()->SetAddress("陕西省西安市雁塔区");
cout << InfoMgr::GetInstance()->GetAddress() << endl;
return 0;
}
总结一下:
饿汉特点:简单一点、初始化顺序不确定,如果有依赖关系就会有问题。饿汉对象初始化慢且多个饿汉单例对象会影响程序启动
懒汉特点:复杂一点。第一次调用时初始化,可以控制初始化顺序,延迟加载初始化,不影响程序启动