1 设计一个不能被拷贝的类
C++类中只有两个拷贝的方式:拷贝构造函数和赋值运算符重载。想要设计一个不能被拷贝的类,只要想办法让类中这两种拷贝的方式不能使用即可。
1.1 C++98的方法
因为在C++的类中,这两种拷贝的方式是默认存在的,所以需要在类中只声明不定义即可。
但是由于在用户在类外还能定义,所以必须将拷贝构造函数和赋值运算符重载设置成private
#include <iostream>
using namespace std;
class copy_ban
{
public:
copy_ban(int x = 0)//有参构造
:_x(x)
{}
private:
int _x;
copy_ban(const copy_ban& co);
copy_ban& operator=(const copy_ban& x);
};
int main()
{
copy_ban c1(1);
copy_ban c2(c1);//error,不能使用拷贝构造
copy_ban c3;
c3 = c1;//error,不能使用赋值运算符重载
return 0;
}
1.2 C++11方法
C++11扩展了delete的用法,在默认成员函数后面加上“=delete”就不允许使用该成员函数了。
#include <iostream>
using namespace std;
class copy_ban
{
public:
copy_ban(int x = 0)//有参构造
:_x(x)
{}
copy_ban(const copy_ban& co) = delete;
copy_ban& operator=(const copy_ban& x) = delete;
private:
int _x;
};
int main()
{
copy_ban c1(1);
copy_ban c2(c1);//error,不能使用拷贝构造
copy_ban c3;
c3 = c1;//error,不能使用赋值运算符重载
return 0;
}
2 设计一个只能在堆上创建对象的类
实现方式:
- 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
- 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
#include <iostream>
using namespace std;
class heap_only
{
public:
heap_only(const heap_only& h) = delete;
static heap_only* create(int x)
{
heap_only* p = new heap_only(x);//new 出来的空间在堆上
return p;
}
private:
int _x;
heap_only(int x = 0) : _x(x){}
};
int main()
{
//heap_only h1(1);//error,构造函数被设置成私有,类外不能使用
heap_only* h2 = heap_only::create(2);//correct,在堆上创建了空间
//heap_only h3(*h2);//error,赋值函数重载加了delete后不能被使用
return 0;
}
3 设计一个只能在栈上创建对象的类
同上将构造函数私有化,然后设计静态方法创建对象返回即可
class stack_only
{
public:
static stack_only create(int x)
{
return stack_only(x);
}
private:
int _x;
stack_only(int x = 0):_x(x){}
};
int main()
{
stack_only s = stack_only::create(1);
return 0;
}
4 设计一个不能被继承的类
4.1 C++98 方式
C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class base
{
private:
base(){}
};
class derived : base
{
};
int main()
{
derived d;//error,派生类调不到基类的构造函数,无法继承
return 0;
}
4.2 C++11方式
final关键字,final修饰类,表示该类不能被继承。
class base final
{
private:
};
class derived : base // error,不能将final类型的类作为基类
{
};
int main()
{
derived d;
return 0;
}
5 设计一个只能创建一个对象的类(单例模式)
单例模式是设计模式里的概念。这里简单介绍一下。
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
单例模式: 一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置 信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再 通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:饿汉模式和懒汉模式
5.1 饿汉模式
饿汉模式 就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
//单例模式
//饿汉模式
class singleton
{
public:
static singleton* get_instance()
{
return _ins;
}
}
private:
singleton(){}//构造函数私有
singleton(const singleton& s) = delete;//防止拷贝
singleton& operator=(const singleton& s) = delete;
private:
static singleton* _ins;
};
singleton* singleton::_ins = new singleton;
//在程序进入入口前就完成单例对象的初始化
使用实例:
现在要求一个类内有vector的类型存放数据,且全局仅允许有一个这样的对象,只能往这个对象里存数据。
//单例模式
//饿汉模式
class singleton
{
public:
static singleton* get_instance()
{
return _ins;
}
void add(const string &s)
{
_v.push_back(s);
}
void print()
{
for (auto& i : _v)
{
cout << i << endl;
}
}
private:
singleton(){}
singleton(const singleton& s) = delete;
singleton& operator=(const singleton& s) = delete;
private:
vector<string> _v;
static singleton* _ins;
};
singleton* singleton::_ins = new singleton;
int main()
{
singleton::get_instance()->add("jack");
singleton::get_instance()->add("luna");
singleton::get_instance()->add("mike");
singleton::get_instance()->print();
return 0;
}
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。
优点:简单
缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
5.2 懒汉模式
懒汉模式是第一次调用get_instance()函数时才创建对象。
class singleton
{
public:
static singleton* get_instance()
{
//这一层判断是为了提高效率,第一次申请加锁保护就可以了,第二次已经不等于空了,不要保护
if (_ins == nullptr)
{
_imtx.lock();//双检查加锁
if (_ins == nullptr)//这一层是为了线程安全问题
{
_ins = new singleton;
}
_imtx.unlock();
}
return _ins;
}
//实现一个内嵌垃圾回收类
class GC
{
public:
~GC()
{
del_instance();
}
};
//定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
static GC _gc;
static void del_instance()
{
_imtx.lock();
if (_ins)
{
delete _ins;
_ins = nullptr;
}
_imtx.unlock();
}
private:
singleton() {}
singleton(const singleton& s) = delete;
singleton& operator=(const singleton& s) = delete;
private:
static singleton* _ins;
static mutex _imtx;
};
singleton* singleton::_ins = nullptr;
mutex singleton::_imtx;
singleton::GC singleton::_gc;
优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控
制。
缺点:复杂文章来源:https://www.toymoban.com/news/detail-552448.html
5.2.1 C++11之后懒汉模式的写法
由于C++11之后保证了静态局部对象的线程安全问题,所以代码可以简化为:文章来源地址https://www.toymoban.com/news/detail-552448.html
//懒汉模式,C++11之后的另一种写法
//C++11可以保证初始化静态对象的线程安全问题
class singleton
{
public:
static singleton* get_instance()
{
//C++11之前不能这样写
//C++11可以保证初始化静态对象的线程安全问题
static singleton _inst;
return &_inst;
}
private:
singleton() {}
singleton(const singleton& s) = delete;
singleton& operator=(const singleton& s) = delete;
};
到了这里,关于【C++学习笔记】特殊类设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!