在实践中,常常会有一些比较有意思的特殊场景:
拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载 因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可 在C++98中我们会将拷贝构造函数和赋值重载函数进行私有化,这样外部就调用不到他们了!
class A
{
A()
{}
~A()
{}
private:
A(const A& a)
{
}
A& operator=(const A& a)
{
}
private:
int _a1;
};
C++11扩展delete
的用法,delete
除了释放new
申请的资源外,如果在默认成员函数后跟上=delete
,表示让编译器删除掉该默认成员函数。
class A
{
A()
{}
~A()
{}
A(const A& a) = delete;
A& operator=(const A& a) = delete;
private:
int _a1;
};
这样就轻松的解决了问题!
使用使用的类,就不能让用户,可以显式调用到构造函数,不然就在栈区创建了对象!我们需要写出一个接口,让用户可以获取到堆上的对象地址!这样就涉及到了先有鸡先有蛋
的问题了,所以我们要将这个接口设置成静态成员函数,才能正常调用!
class HeapOnly
{
public:
static HeapOnly* CreateObj()
{
return new HeapOnly;
}
private:
HeapOnly()
{
}
HeapOnly(const HeapOnly& h) = delete;
HeapOnly& operator=(const HeapOnly& a) = delete;
private:
int _a1;
};
注意:除了处理构造函数,还要处理拷贝构造和赋值拷贝函数。因为拷贝的对象也是在栈上的!必须把所有可能的方法都要封死!
这样一个只能在堆上创建对象的类就写好了!
还有一个十分新奇的写法:将析构函数私有化!这样在栈上创建对象就会报错,迫使用户只能在堆上构造对象!我们可以通过一个显式的release
方法来释放空间,来完善在堆上创建对象的操作!
同上将构造函数私有化,然后设计静态方法创建对象返回.注意为了防止在堆上创建对象,我们需要将new delete
操作符重载函数进行删除!这样就将在堆上创建彻底封死了!
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:
StackOnly()
:_a(0)
{}
private:
int _a;
};
回顾一下继承的知识:从零开始认识继承
不能被继承的类很简单!C++98是将构造函数进行私有化,在C++11之后直接使用final
关键字就可以了!
class A final
{
// ....
};
C++的世界里,一些特别的类真是挺有讲究的。就像游戏里的独门魔法宝物,模拟豪华游艇的细节,还有银行系统里那些用完就丢的密码,每一个都是针对特定情况精心设计的。那些不能复制的类,就像是在说“我是特别的,不能随便复制”;只能在堆上或者栈上创建对象的类,就像是给内存管理上了把锁,保证了东西放在该放的地方;而不让继承的类,就像是定了规矩,让功能保持原汁原味。
这些设计不仅展示了C++的强大,也让我们看到程序员先辈们是如何巧妙地解决难题的。通过这几个特殊的类,我们的代码能力肯定有许多长进,C++的学习过程也变得更加丰富多彩了!