目录
设计一个类不能被拷贝
C++98的做法:将拷贝构造和赋值重载只声明不实现,并设为私有,为什么要声明,因为它们是默认成员函数,我们不写编译器会自动生成
C++11做法:直接用delete
设计一个类,只能在堆上创建对象
方法一:析构函数私有
这时候就无法直接创建对象,但是可以new对象,因为析构函数私有,这时创建对象没办法自动调用析构,怎么释放呢,许愿写一个公有的释放函数通过new返回的指针去调用释放函数
class HeapOnly
{
private:
~HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
HeapOnly ho; //无法自动调用析构
HeapOnly* ptr = new HeapOnly;
delete ptr; //无法调用析构
return 0;
}
静态公有释放函数
class HeapOnly
{
public:
static void Destroy(HeapOnly* ptr)
{
delete ptr;
}
private:
~HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
//HeapOnly ho; //无法自动调用析构
HeapOnly* ptr = new HeapOnly;
//delete ptr; //无法调用析构
HeapOnly::Destroy(ptr);
return 0;
}
更好的写法,直接delete this
class HeapOnly
{
public:
void Destroy()
{
delete this;
}
private:
~HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
HeapOnly* ptr = new HeapOnly;
ptr->Destroy();
return 0;
}
方法二:构造函数私有
这时无论是直接创建对象还是new对象都不行了,
class HeapOnly
{
public:
private:
HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
HeapOnly h1;
HeapOnly* ptr = new HeapOnly;
return 0;
}
需要写一个公有函数来创建
但是这里却无法调用Creat(),因为这里调用这个函数得先有对象,但是我调用这个函数的原因就是我要创建对象,这里就可以用静态来解决
class HeapOnly
{
public:
HeapOnly* Creat()
{
return new HeapOnly;
}
private:
HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
HeapOnly* ptr = Creat(); //调用不了
return 0;
}
class HeapOnly
{
public:
static HeapOnly* Creat()
{
return new HeapOnly;
}
private:
HeapOnly()
{
cout << "~" << endl;
}
};
int main()
{
HeapOnly* ptr = HeapOnly::Creat();
return 0;
}
有一个缺陷就是通过拷贝构造也能在栈上创建,所以要把拷贝构造给禁了
设计一个类,只能在栈上创建对象
先把构造函数私有,然后写一个静态的公有创建函数
class StackOnly
{
public:
static StackOnly Creat()
{
StackOnly s1;
return s1;
}
private:
StackOnly()
{
cout << "s" << endl;
}
};
int main()
{
StackOnly s = StackOnly::Creat();
return 0;
}
有一个缺陷,就是可以通过拷贝构造创建,这里如果单纯禁掉拷贝构造的话,那个公有函数的传值返回就无法实现,
new分为operator new 和 调用拷贝构造,operator new是全局的,但如果类内写了一个就会调类内的,new这个对象的时候就会调类内的不会调全局的,所以我们可以把operator new禁掉,相当于间接禁掉new
StackOnly* ptr = new StackOnly(s);
设计一个类,不能被继承
C++98做法:构造函数私有,派生类就调不到基类的构造函数则无法继承
C++11做法:final表示该类不能被继承
设计一个类,只能创建一个对象(单例模式)
单例模式是一种设计模式,设计模式是代码设计的经验总结
单例是指全局只有一个唯一的实例对象,单例模式分为饿汉模式和懒汉模式,饿汉:提前创建好,main函数启动时创建好实例对象,懒汉:第一次用的时候再创建
饿汉
先把构造函数和拷贝构造私有,创建一个A类型的静态成员,因为静态成员不在对象里面,是存在静态区的,类内声明类外定义,然后提供一个该成员地址的静态公有函数,通过这个函数获取到这一个唯一对象的地址。
class A
{
public:
static A* GetInstance()
{
return &_inst;
}
void print()
{
}
private:
A()
{}
A(const A& aa) = delete;
A& operator=(const A& aa) = delete;
static A _inst;
};
A A::_inst;
int main()
{
A::GetInstance()->print();
return 0;
}
饿汉模式的优点:相比懒汉实现简单,缺点:1. 可能会导致进程启动慢,2. 无法控制单例先后启动顺序
懒汉
在饿汉的基础上把静态成员的类型变成指针,在类外定义为空,
获取对象的函数也需要修改
static B* GetInstance()
{
if (_Binst == nullptr)
{
_Binst = new B;
}
return _Binst;
}
int main()
{
B::GetInstance()->print();
return 0;
}
析构问题
new的懒汉对象一般不需要释放,进程正常结束会释放,但有时候我们需要在析构做点事情比如持久化处理,想要让进程结束时调用析构,首先弄一个gc内部类,创建一个gc静态对象,在main函数结束它会调用析构函数,
class B
{
public:
static B* GetInstance()
{
if (_Binst == nullptr)
{
_Binst = new B;
}
return _Binst;
}
void print()
{
}
static void DelInstance()
{
if (_Binst)
{
delete _Binst;
_Binst = nullptr;
}
}
private:
B()
{}
~B()
{
cout << "hhh" << endl;
}
B(const B& aa) = delete;
B& operator=(const B& aa) = delete;
static B* _Binst;
class gc
{
public:
~gc()
{
DelInstance();
}
};
static gc _gc;
};
B* B::_Binst = nullptr;
B::gc B::_gc;