1 创建只能在堆上创建的类
创建只能在堆上创建的类基本思路是让其在栈上创建失败。在栈上创建类程序需要调用构造器和析构器对类对象进行初始化和销毁。
让程序调用析构函数和构造函数失败的实现方式就是将析构函数声明为private或者protected。
1.1 析构函数和构造函数全部私有?
最直接的一种写法便是将析构函数和构造函数私有化,另外创建对象创建的接口,只通过在堆上创建相关的对象指针。
class test
{
private:
test(){}
~test(){}
public:
static test* create_instance()
{
return new test;
}
static void delete_instance(test **ptr)
{
delete *ptr;
*ptr = nullptr;
}
};
int main() {
test test_instance; //编译错误,无法调用私有的构造函数
test *ptr = test::create_instance();
test::delete_instance(&ptr);
if(ptr == nullptr)
{
cout<<"删除成功"<<endl;
}
}
完全可以只对析构函数进行私有化处理。这样做的好处是,可以通过new
操作符创建对象的指针,如果需要通过重载new
进行额外的操作时,完全可以按照最初的方式进行操作。这种方式本着最小的修改达到目的地原则进行改进。
#include <iostream>
#include <vector>
using namespace std;
class test
{
public:
test(){}
private:
~test(){}
public:
static test* create_instance()
{
return new test;
}
static void delete_instance(test **ptr)
{
delete *ptr;
*ptr = nullptr;
}
};
int main() {
//test test_instance; //编译错误,无法调用私有的析构函数
test *ptr = test::create_instance();
test *new_ptr = new test;
test::delete_instance(&ptr);
test::delete_instance(&new_ptr);
if(ptr == nullptr && nullptr == new_ptr)
{
cout<<"删除成功"<<endl;
}
}
当然也可以只对构造函数进行私有化,这时便可以使用delete删除对象。
#include <iostream>
#include <vector>
using namespace std;
class test
{
private:
test(){}
public:
~test(){}
public:
static test* create_instance()
{
return new test;
}
static void delete_instance(test **ptr)
{
delete *ptr;
*ptr = nullptr;
}
};
int main() {
//test test_instance; //编译错误,无法调用私有的析构函数
test *ptr = test::create_instance();
test::delete_instance(&ptr);
if(ptr == nullptr )
{
cout<<"删除成功"<<endl;
}
}
需要注意的是以上三种方式的区别:
- 构造析构都私有化:对象只能存在于堆上,存在于栈上的对象只能存活在当前类的相关函数中;
- 仅仅构造私有化:严格意义上来说可以通过当前函数获取栈上的对象,因为析构未私有,也是可以有效销毁的;
- 仅仅析构私有化:对象只能存在于堆上,存在于栈上的对象只能存活在当前类的相关函数中。
1.2 private还是protected?
priavte和protected的区别是在继承上。如果需要对创建的类进行继承,使用private
就会出现子类无法调用父类的构造函数构造父类,从而导致创建失败或者无法调用类的析构函数导致销毁失败的情况。如果使用protected
,对于继承体系的外部来说,仍然有权限隔离,只能创建堆上的对象。
#include <iostream>
#include <vector>
using namespace std;
class test
{
public:
test(){}
protected:
~test(){}
public:
static test* create_instance()
{
return new test;
}
static void delete_instance(test **ptr)
{
delete *ptr;
*ptr = nullptr;
}
};
class driverd_test : public test
{
public:
driverd_test(){}
protected:
~driverd_test(){}
static driverd_test* create_instance()
{
return new driverd_test;
}
static void delete_instance(driverd_test **ptr)
{
delete *ptr;
*ptr = nullptr;
}
};
int main() {
//test test_instance; //编译错误,无法调用私有的析构函数
test *ptr = test::create_instance();
test::delete_instance(&ptr);
if(ptr == nullptr )
{
cout<<"删除成功"<<endl;
}
//riverd_test instance; //编译错误,无法调用私有的析构函数
test *new_ptr = test::create_instance();
test::delete_instance(&new_ptr);
if(new_ptr == nullptr )
{
cout<<"子类删除成功"<<endl;
}
}
需要注意的是使用protected
和private
的区别:
private
:栈上的对象仅仅能存在于当前类中;protected
:栈上的对象能存在于当前继承体系中;
2 创建只能在栈上创建的类
只能在栈上创建的对象基本原则是让对象在堆上创建失败。
2.1 垄断构造渠道
可以通过上面类似的方式对构造函数私有化,通过自定义的静态函数获取类对象。
class test
{
private:
test(){};
public:
static test get_object()
{
return test();
}
};
2.2 禁止new和delete操作符的调用
通过将operator new
和operator delete
私有化或者protected来控制访问权限。
class test
{
private:
void* operator new(size_t size);
void operator delete(void* p);
void* operator new[](size_t size);
void operator delete[](void* p);
public:
static test get_object()
{
return test();
}
};
int main() {
//test test_instance; //编译错误,无法调用私有的析构函数
test a;
test *p = new test; //无法访问
}
通过将operator new
和operator delete
申明为delete
限制访问。
#include <iostream>
#include <vector>
using namespace std;
class test
{
public:
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
void* operator new[](size_t size) = delete;
void operator delete[](void* p) = delete;
public:
static test get_object()
{
return test();
}
};
int main() {
//test test_instance; //编译错误,无法调用私有的析构函数
test a;
test *p = new test; //无法访问
}
3 创建不能被继承的类
创建不能被继承的类的基本原理还是访问控制。当前类不能被继承,但是必须包含类的所有特性因此不能在当前类上做手脚。可以声明一个无用的类,其构造函数和析构函数设为私有,只有当前类能够访问,这样当别的类要继承当前类时必然需要调用基类的构造函数,但是因为没有权限导致继承失败。
其中grad_father
类是继承失败的。
#include <iostream>
#include <vector>
using namespace std;
class child
{
friend class father;
private:
child(){};
~child(){};
};
class father : virtual public child
{
};
//继承失败
class grad_father : public father
{
public:
grad_father(){};
~grad_father();
};
int main() {
father f;
grad_father ff;
}
另一种简单的实现方式是通过关键字final
:
class base final{};
class derived : public base{}; //继承失败