C++:特殊类设计和四种类型转换
一、特殊类设计
1.1 不能被拷贝的类
拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
C++98:
1、将拷贝构造函数与赋值运算符重载只声明不定义。(防自己人)
不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就可能导致成员函数进行内部拷贝了。
2、并且将其访问权限设置为私有即可。(防外人)
如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了
class CopyBan { // ... private: CopyBan(const CopyBan& c); CopyBan& operator=(const CopyBan& c); //... };
C++11:
C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟=delete,表示让编译器删除掉该默认成员函数。
class CopyBan { // ... CopyBan(const CopyBan& c)=delete; CopyBan& operator=(const CopyBan& c)=delete; //... };
1.2 只能在堆上创建对象的类
思路1:
1. 将类的构造函数私有,拷贝构造声明成私有(可以直接delete掉)。防止别人调用拷贝在栈上生成对象。
注意:拷贝构造可以直接delete掉,但是构造函数不行!!因为我们还需要利用构造函数在堆上创建对象。
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
注意:这里涉及到的是先有鸡还是先有蛋的问题,因为如果不去创建这个对象就没有办法去调用他的构造函数,但是没有调用构造函数就没有办法创建对象。所以这里必须通过静态成员函数的返回值去构造堆对象。
class HeapOnly { public: static HeapOnly* CreateObject() { return new HeapOnly; } private: HeapOnly(){}; HeapOnly(const HeapOnly&) = delete; }; int main() { HeapOnly*p = HeapOnly::CreateObject(); return 0; }
思路2:
1、相比较于上一种思路把构造函数私有、拷贝构造delete,也可以选择将析构函数给设成私有。
析构函数设置成私有同样会导致对象无法在栈上进行创建。因为自定义类型在栈帧中销毁的时候会去自动调用他的析构函数,但是因为调不到所以会报错。
2、封装一个destory的成员函数,这样我们可以手动释放堆空间的资源。
在堆上创建对象是用指针去接受,所以并不影响,但是内存需要我们去手动释放,因此我们需要封装destory的成员函数去调用delete,这样delete可以对应调用到析构函数。 这里有两个方案:一种是设置能静态成员函数(类域调用),一种是设置成普通成员函数(对象自己调用)。
class HeapOnly { public: //方案1 static void Destroy(HeapOnly* hp) { delete hp; } //方案2 void Destroy() { delete this; } private: ~HeapOnly() {}; }; int main() { //HeapOnly H; 调不到析构函数,无法创建 //静态成员函数释放 HeapOnly* ptr = new HeapOnly; HeapOnly::Destroy(ptr); //普通成员函数释放 HeapOnly* ptr2 = new HeapOnly; ptr2->Destroy(); return 0; }
1.3 只能在栈上创建对象的类
1、new和delete是全局的运算符重载函数,因此我们只要将这两个给禁用掉,就不会在堆上创建对象。
需了解具体声明:void* operator new(size_t size) 和 void operator delete(void* p) 。实现类专属的operator new和delete 这样new这个类对象时,operator new就会调用这个,不会调全局的。
class StackOnly { public: static StackOnly CreateObj() { return StackOnly(); } // 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉 // StackOnly obj = StackOnly::CreateObj(); // StackOnly* ptr3 = new StackOnly(obj); void* operator new(size_t size) = delete; void operator delete(void* p) = delete; private: int _a; }; int main() { StackOnly obj; //StackOnly* s = new StackOnly; }
但是没有办法去禁用C语言的相关函数。
1.4 不能被继承的类
C++98:
构造函数私有化,这样子类调用不到父类的构造函数,无法实现继承
class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };
C++11:
直接用final关键字,可以使得该类无法被继承
class A final { // .... };
1.5 控制可创建对象数量的类
设置一个静态int变量count,每创建一个对象就--count
class singleclass { public: static singleclass* getsingleclass() { if (count > 0) { count--; return new singleclass(); } else { cout