主页 > 创业  > 

C++特殊类设计

C++特殊类设计

C++特殊类设计 1、请设计一个类,不能被拷贝2、请设计一个类,只能在堆上创建对象3、请设计一个类,只能在栈上创建对象4、请设计一个类,不能被继承5、请设计一个类,只能创建一个对象(单例模式)5.1、饿汉模式5.2、懒汉模式

1、请设计一个类,不能被拷贝

拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C++98方式:将拷贝构造和赋值私有

class CopyBan { public: CopyBan() {} private: CopyBan(const CopyBan& cb); CopyBan& operator=(const CopyBan& cb); };

1. 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了 2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。


C++11方式:扩展delete用法

class CopyBan { public: CopyBan() {} CopyBan(const CopyBan& cb) = delete; CopyBan& operator=(const CopyBan& cb) = delete; };

C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。


2、请设计一个类,只能在堆上创建对象

方式一:析构函数私有

class HeapOnly { public: void Destroy() { delete this; } private: ~HeapOnly() {} }; HeapOnly* hp = new HeapOnly; hp->Destroy();

在栈上创建的对象除了作用域会自动调用析构函数,析构函数私有就无法调用了,所以无法在栈上创建对象。 可以在堆上创建对象,但是有个问题,delete的时候无法调用析构函数,因为delete的原理是析构函数+释放空间,所以我们提供一个Destroy接口,直接在函数内部delete,这样就可以调用析构函数。


方式二:构造函数私有

class HeapOnly { public: static HeapOnly* CreateObj() { return new HeapOnly; } private: HeapOnly() {} HeapOnly(const HeapOnly& hp) = delete; HeapOnly& operator=(const HeapOnly& hp) = delete; }; HeapOnly* hp = HeapOnly::CreateObj();

构造函数私有后,既不能在栈上创建,也不能在堆上创建。因此我们需要提供一个CreateObj函数,在里面创建然后将指针返回给外部接收,并且这个函数必须是静态的,否则调不到。

但是这样还是防不住下面这种方式:

HeapOnly* hp = HeapOnly::CreateObj(); HeapOnly copy(*hp);

所以还需要防拷贝。


3、请设计一个类,只能在栈上创建对象

方式:构造函数私有

class StackOnly { public: static StackOnly CreateObj() { StackOnly st; return st; } private: StackOnly() {} void* operator new(size_t size) = delete; }; StackOnly st1 = StackOnly::CreateObj();

构造函数私有,然后提供一个静态成员函数,在该成员函数里面创建对象返回。 但是还是防不住下面这种情况:

StackOnly* hp = new StackOnly(st1);

new的原理就是operator new加构造函数,所以我们需要禁掉operator new。


4、请设计一个类,不能被继承

C++98方式:构造函数私有

class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };

C++11方式:final修饰

class A final { // ... };
5、请设计一个类,只能创建一个对象(单例模式)

单例模式: 一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。 单例模式有两种实现模式:饿汉模式和懒汉模式。

5.1、饿汉模式

之前的CreateObj,不管是new还是栈上创建再返回,都是不同的对象,现在需要的是同一个对象,思考一下该怎么做?

namespace hungry { class Singleton { public: static Singleton& GetInstance() { return _sinst; } void Add(const pair<string, string>& kv) { _dict[kv.first] = kv.second; } void Print() { for (const auto& e : _dict) { cout << e.first << ":" << e.second << endl; } cout << endl; } private: Singleton() {} Singleton(const Singleton& s) = delete; Singleton& operator=(const Singleton& s) = delete; map<string, string> _dict; // ... static Singleton _sinst; }; Singleton Singleton::_sinst; } int main() { cout << &hungry::Singleton::GetInstance() << endl; cout << &hungry::Singleton::GetInstance() << endl; cout << &hungry::Singleton::GetInstance() << endl; hungry::Singleton::GetInstance().Add({ "xxx", "111" }); hungry::Singleton::GetInstance().Add({ "yyy", "222" }); hungry::Singleton::GetInstance().Add({ "zzz", "333" }); hungry::Singleton::GetInstance().Print(); return 0; }

实现: 1、首先将构造函数私有。 2、声明静态类对象,然后在类外定义,提供一个获取对象的静态成员函数GetInstance()。 3、防拷贝,将拷贝和赋值声明为删除。

饿汉模式:就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。 但是也有下面的问题: 1、如果单例对象初始化内容很多,影响启动速度。 2、如果有两个单例类,相互依赖关系。假设有A、B两个单例类,要求先创建A,然后再创建B,B的初始化依赖A。


5.2、懒汉模式 namespace lazy { class Singleton { public: static Singleton& GetInstance() { if (_psinst == nullptr) { _psinst = new Singleton; } return *_psinst; } static void DelInstance() { if (_psinst) { delete _psinst; _psinst = nullptr; } } void Add(const pair<string, string>& kv) { _dict[kv.first] = kv.second; } void Print() { for (const auto& e : _dict) { cout << e.first << ":" << e.second << endl; } cout << endl; } private: Singleton() {} Singleton(const Singleton& s) = delete; Singleton& operator=(const Singleton& s) = delete; ~Singleton() { cout << "~Singleton()" << endl; // map数据写到文件中 FILE* fin = fopen("map.txt", "w"); for (auto& e : _dict) { fputs(e.first.c_str(), fin); fputs(":", fin); fputs(e.second.c_str(), fin); fputs("\n", fin); } } map<string, string> _dict; // ... static Singleton* _psinst; }; Singleton* Singleton::_psinst = nullptr; }

懒汉模式:第一次调用GetInstance的时候创建单例对象 那么如何释放呢?单例一般不用释放,进程结束直接带走了。 特殊场景:1、中途需要显示释放 2、程序结束时,需要做一些特殊动作(如持久化) 上面的析构函数就是场景2,假设需要把数据写入文件,那么如果是进程结束是不会走析构函数的,无法做到数据持久化。 所以可以提供一个DelIstance函数,中途可以显示释放:

cout << &lazy::Singleton::GetInstance() << endl; cout << &lazy::Singleton::GetInstance() << endl; cout << &lazy::Singleton::GetInstance() << endl; lazy::Singleton::GetInstance().Add({ "xxx", "111" }); lazy::Singleton::GetInstance().Add({ "yyy", "222" }); lazy::Singleton::GetInstance().Add({ "zzz", "333" }); lazy::Singleton::GetInstance().Print(); lazy::Singleton::GetInstance().DelInstance();


那么如果我不想显示释放,并且还希望数据持久化呢? 可以写这么一个类:

class GC { public: ~GC() { lazy::Singleton::GetInstance().DelInstance(); } }; GC gc;

还可以直接写在Singleton内部:

namespace lazy { class Singleton { public: static Singleton& GetInstance() { if (_psinst == nullptr) { _psinst = new Singleton; } return *_psinst; } static void DelInstance() { if (_psinst) { delete _psinst; _psinst = nullptr; } } void Add(const pair<string, string>& kv) { _dict[kv.first] = kv.second; } void Print() { for (const auto& e : _dict) { cout << e.first << ":" << e.second << endl; } cout << endl; } class GC { public: ~GC() { lazy::Singleton::GetInstance().DelInstance(); } }; private: Singleton() {} Singleton(const Singleton& s) = delete; Singleton& operator=(const Singleton& s) = delete; ~Singleton() { cout << "~Singleton()" << endl; // map数据写到文件中 FILE* fin = fopen("map.txt", "w"); for (auto& e : _dict) { fputs(e.first.c_str(), fin); fputs(":", fin); fputs(e.second.c_str(), fin); fputs("\n", fin); } } map<string, string> _dict; // ... static Singleton* _psinst; static GC _gc; }; Singleton* Singleton::_psinst = nullptr; Singleton::GC Singleton::_gc; } int main() { cout << &lazy::Singleton::GetInstance() << endl; cout << &lazy::Singleton::GetInstance() << endl; cout << &lazy::Singleton::GetInstance() << endl; lazy::Singleton::GetInstance().Add({ "xxx", "111" }); lazy::Singleton::GetInstance().Add({ "yyy", "222" }); lazy::Singleton::GetInstance().Add({ "zzz", "333" }); lazy::Singleton::GetInstance().Print(); return 0; }

标签:

C++特殊类设计由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++特殊类设计