C++之特殊类设计及类型转换
目录
一、设计一个不能被拷贝的类
二、设计一个只能在堆上创建对象的类
三、设计一个只能在栈上创建对象的类
四、设计一个不能被继承的类
五、设计一个只能创建一个对象的类(单例模式)
六、C语言中的类型转换
七、C++中的三类类型转换
八、C++强制类型转换
8.1、为什么C++需要四种类型转换
8.2、static_cast
8.3、reinterpret_cast
8.4、const_cast
8.5、dynamic_cast
九、RTTI
一、设计一个不能被拷贝的类
拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
C++98:
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。
原因:
- 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不被禁止拷贝了
- 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
示例代码:
class CopyBan { private: CopyBan(const CopyBan&); CopyBan& operator=(const CopyBan&); //... };
C++11:
C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上
=delete,表示让编译器删除掉该默认成员函数。
示例代码:
class CopyBan { // ... CopyBan(const CopyBan&) = delete; CopyBan& operator=(const CopyBan&) = delete; //... };
二、设计一个只能在堆上创建对象的类
实现方式:
1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
方法一:
class HeapOnly { public: //提供在堆上创建对象的方法 static HeapOnly* CreateObj() { return new HeapOnly; } //将拷贝构造和赋值重载也禁止 HeapOnly(const HeapOnly&) = delete; HeapOnly& operator=(const HeapOnly&) = delete; private: //将构造私有,防止外界直接创建对象 HeapOnly() {} }; int main() { //静态区上创建对象 //static HeapOnly hp0; // 栈上创建对象 //HeapOnly hp1; //堆上创建对象 //HeapOnly* hp2 = new HeapOnly; HeapOnly* hp3 = HeapOnly::CreateObj(); //要防止别人通过这种方式在栈上创建对象 //通过禁止拷贝构造来防止这种方式 //HeapOnly hp4(*hp3); //手动释放堆上的资源 delete hp3; return 0; }
解释:上面代码是通过私有构造函数的方式来阻止外界自己创建对象,并提供一个在堆上创建对象的方法,使得外界只能在堆上创建对象,将拷贝构造和赋值重载禁止是防止别人像图中那样通过这两个方法在栈上创建对象。
方法二:
class HeapOnly { public: void Destroy() { delete this; } private: //析构函数私有化 ~HeapOnly() {} }; int main() { //static HeapOnly hp0; //HeapOnly hp1; HeapOnly* hp2 = new HeapOnly; //delete hp2; hp2->Destroy(); return 0; }
解释:该方法是通过私有析构函数的方式使外界无法自动调用析构函数,进而无法创建对象,只能在堆上创建对象,因为在堆上申请的空间需要自己主动释放,不会自动调用析构。这种实现的方法无需禁止拷贝构造和赋值重载,因为通过这两种方式创建出来的栈上的对象仍会因为无法调用析构而无法创建。
三、设计一个只能在栈上创建对象的类
方法一:同上将构造函数私有化,然后设计静态方法创建对象返回,并禁止掉重载的new和delete。
class StackOnly { public: static StackOnly CreateObj() { return StackOnly(); } //StackOnly(const StackOnly& s) = delete; void* operator new(size_t size) = delete; void operator delete(void* p) = delete; private: StackOnly() :_a(0) {} private: int _a; }; int main() { //static StackOnly s1; //StackOnly s2; //StackOnly* s3 = new StackOnly; StackOnly s4 = StackOnly::CreateObj(); //StackOnly* s5 = new StackOnly(s4); static StackOnly s6(s4); return 0; }
解释:私有构造函数,并提供创建对象的方法,这样外界无法自己创建对象,只能使用提供的方法在栈上创建对象。但如果只是这样外界可以通过拷贝构造在堆上或在静态区创建对象,可我们不能禁止掉拷贝构造,因为在栈上创建对象并返回,会用到拷贝构造,如上述代码中s4接收返回的栈上的对象就是将栈上的对象拷贝给s4的,所以我们重载new和delete,C++中如果我们重载了这两个方法,那么我们调用这两个方法时会优先调用我们自己的而不是库的,我们再将这两个方法禁止,这样就阻止别人在堆上创建对象了。但是在静态区禁止不了。
方法二:同上将构造函数私有化,然后设计静态方法创建对象返回,并禁止掉拷贝构造,但提供移动构造。
class StackOnly { public: static StackOnly CreateObj() { return StackOnly(); } StackOnly(const StackOnly&& s) { //...... } StackOnly(const StackOnly& s) = delete; private: StackOnly() :_a(0) {} private: int _a; }; int main() { StackOnly s4 = StackOnly::CreateObj(); //StackOnly* s5 = new StackOnly(s4); //static StackOnly s6(s4); //这种方式禁止不掉 StackOnly* s5 = new StackOnly(move(s4)); static StackOnly s6(move(s4)); return 0; }
解释:提供的在栈上创建对象的方法返回的是匿名对象,是右值,可以通过移动构造赋值出去,这样外界用事先创建好的对象再通过拷贝的方式在堆上或者在静态区创建对象就创建不了了,但如果有人将左值move成右值再去拷贝,那就阻止不了了。
四、设计一个不能被继承的类
C++98方式:构造函数私有化,派生类中调不到基类的构造函数。则无法继承
示例代码:
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承 class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };
C++11方法:final关键字,final修饰类,表示该类不能被继承。
示例代码:
class A final { // .... };
五、设计一个只能创建一个对象的类(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的 总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打 仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后 来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模 式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个 访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置 信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再 通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:
- 饿汉模式
就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
// 饿汉模式 // 1、多个饿汉模式的单例,某个对象初始化内容较多(读文件),会导致程序启动慢 // 2、A和B两个饿汉,对象初始化存在依赖关系,要求A先初始化,B再初始化,饿汉无法保证 class InfoMgr { public: static InfoMgr& GetInstance() { return _ins; } void Print() { cout
- 饿汉模式