1.设计一个类不能拷贝
cpp
class NotCopy
{
//只声明不实现!
public:
private:
NotCopy(const NotCopy&);
NotCopy& operator=(const NotCopy&);
//还有一种方法就是,c++11里面的加关键字delete
};
2.设计一个类只能在堆上创建对象
cpp
class HeapOnly
{
public:
//在这里我需要解释的是,肯定会有疑问为什么要用静态成员函数!
//首先如果不用静态成员,普通函数放在类里面,如果在类外面想要被调用,首先得先实例化一个对象,然后才能调用!
//然后因为我们为了实现在堆上创建对象,所以我们把构造函数和析构函数都进行了私有化,所以我们直接在栈上实例化对象是不可能了
//因此我们没有了对象,现在要调用函数只能通过静态函数,因为静态函数它不需要通过对象调用,它自己就是可以看做类本身,加上作用域就可以了
static HeapOnly* creat()
{
return new HeapOnly;
}
//静态函数属于类本身,不属于类的某个具体对象实例 ,它可以在不依赖对象实例的情况下被调用
static void destory(HeapOnly* ptr)
{
delete ptr;
}
HeapOnly(const HeapOnly& hp) = delete;//这里把拷贝构造禁止掉!
private:
//方案一,析构函数私有化!
HeapOnly() {};
~HeapOnly(){}
};
3.设计一个类只能在栈上创建对象
cpp
class StackOnly
{
public:
static StackOnly creat()
{
StackOnly obj;//这是在栈上面!
return obj;
}
//如果你有实现一个专属类的operator new这样,它会优先调用自己的,不会去用库里面的!
/*void* operator new(size_t size)
{
cout << "void* operator new" << endl;
return malloc(size);
}*/
//所以通过上面这种操作,其实可以在自己的类里面把operator new给ban掉
void* operator new(size_t size) = delete;
/*~StackOnly();*/
private:
StackOnly()
{
cout << "stackonly" << endl;
}
};
4.设计一个不能被继承的类
cpp
class NotInherit
{
//方案一:构造函数私有化!
// 因为当你父类构造函数私有化的时候,
// 你子类创建对象的时候会初始化列表的时候先要调用父类构造函数初始化父类的变量!
//方案二就是给类加final
private:
NotInherit(){}
};
5.请设计一个类,只能创建一个对象(单例模式)
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。在我看来就是5v5,然后4打5有一个人去偷塔。
方案一:饿汉模式 -把对象提前创建好(程序启动时:main函数启动时),饿了直接吃!
想一想什么对象,可以在main函数前创建好,答案肯定可以想到全局变量!
优点:实现简单
缺点:进程启动慢,如果两个单例启动又先后顺序,饿汉模式无法控制!
cpp
class A
{
public:
static A* getInstance()
{
return &inst;
}
void add(const string& k,const string&v)
{
dict[k] = v;
}
void print()
{
for (auto e : dict)
{
cout << e.first <<": " << e.second << endl;
}
cout << endl;
}
private:
A(){}
map<string, string> dict;
int _n = 0;
//把拷贝构造和赋值都禁掉,防止出现多个单例!
A(const A& aa) = delete;
A& operator=(const A& aa) = delete;
static A inst;//这里是声明,静态成员变量要在类外面定义!
};
A A::inst;
//A inst;//全局!它是会有很多缺陷的,当你把全局放在.h里面多个cpp都能用到它,会出现连接错误的!
方案二:懒汉模式 -第一次用的时候再创建(现吃现做)
//new的懒汉对象一般不需要释放 进程自然结束,会自动释放资源;这里的释放资源其实是解除页表式的释放资源!
cpp
class B
{
public:
static B* getInstance()
{
if (inst == nullptr)
{
inst = new B;
//如果写成 new B* ,得到的指针指向的是一个存储 B 类指针的空间,
// 并非实际的 B 类对象,后续无法通过 inst 正确操作期望的单例对象。
}
return inst;
}
void add(const string& k, const string& v)
{
dict[k] = v;
}
void print()
{
for (auto e : dict)
{
cout << e.first << ": " << e.second << endl;
}
cout << endl;
}
//如果你需要手动释放资源你就调用下面的函数!,给它设置成静态全局变量是因为可以让整个类都能访问到!
static void DelInstance()
{
if (inst)
{
delete inst;
inst = nullptr;
}
}
private:
B() {}
map<string, string> dict;
int _n = 0;
//把拷贝构造和赋值都禁掉,防止出现多个单例!
B(const B& bb) = delete;
B& operator=(const B& bb) = delete;
static B* inst;//这里是声明,静态成员变量要在类外面定义!
//内部类,是外部类的的友元
class del
{
public:
~del()
{
DelInstance();
}
};
static del D;//之所以有静态全局对象是因为,要触发del的析构函数,
//而为什么用静态是因为只有静态成员其实是main程序结束后,系统开始清理资源时才会被释放
};
B* B::inst=nullptr;
B::del B:: D;
void test()
{
/*StackOnly obj= StackOnly::creat();*/
//虽然禁止了下面这个玩法,但是
/*int* _ptr = new int;
StackOnly* ptr = _ptr;*/
/*StackOnly* ptr = new StackOnly(obj);*///这种情况也是能在堆上创建的!,所以解决它的办法就是去弄一个自己的类new
//不管你调用什么函数,得先单例出来一个对象才可以!
B::getInstance()->add("sort", "排序");
B::getInstance()->add("interator", "迭代器");
/*A::print();错误写法!*/
B::getInstance()->print();
//为了防止多个单例出现所以要禁掉拷贝构造!
}
单例模式细节(未完结)