【C++】特殊类设计 — 不能被拷贝的类 , 只能在堆/栈上创建对象的类 ,不能被继承的类

CSDN 2024-08-26 13:05:04 阅读 80

在这里插入图片描述

苟活者在淡红的血色中,会依稀看见微茫的希望;

真的猛士,将更奋然而前行。

--- 鲁迅 ---


@toc

1 特殊类

在实践中,常常会有一些比较有意思的特殊场景:

不能被拷贝的类 - 独一无二的魔法宝物:

在一个角色扮演游戏(RPG)。在这个游戏中,玩家可以通过工匠进行装备的拷贝,但是有一件神秘的魔法宝物,被称为“永恒之心”,它拥有赋予持有者永生的力量 ,是独一无二的,因此它不能被复制或克隆。

每当玩家尝试复制“永恒之心”时,游戏会抛出一个错误:“魔法宝物独一无二,无法复制!”。这确保了游戏中只有一个“永恒之心”,增加了它的神秘感和价值。只能在堆上创建对象的类 - 豪华游艇

有一个豪华游艇模拟器。在这个模拟器中,游艇是一个复杂且昂贵的对象,它需要在堆上动态分配资源,比如内存来存储游艇的详细规格和状态。

每当玩家想要创建一艘新的游艇时,他们必须通过“造船厂”接口来请求,这实际上是在堆上分配了一个新的游艇对象。只能在栈上创建对象的类 - 一次性密码

你正在为银行的安全系统编写代码。为了防止密码被复制或存储在不可靠的地方,你设计了一个“一次性密码”类,它只能在栈上创建,并在使用后立即销毁

当用户进行一次交易时,系统会生成一个一次性密码,一旦交易完成,密码就会“消失”,保证了密码的安全性。

在这些特殊场景中,我们需要按照需求设计是特殊类!

2 不能被拷贝的类

拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载

因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可

在C++98中我们会将拷贝构造函数和赋值重载函数进行私有化,这样外部就调用不到他们了!

<code>class A

{ -- -->

A()

{ }

~A()

{ }

private:

A(const A& a)

{

}

A& operator=(const A& a)

{

}

private:

int _a1;

};

必须设置成私有:如果只声明没有设置成private,如果在类外定义拷贝构造和赋值重载,就不能禁止拷贝了!只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不能防止成员函数内部拷贝了!

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

class A

{

A()

{ }

~A()

{ }

A(const A& a) = delete;

A& operator=(const A& a) = delete;

private:

int _a1;

};

这样就轻松的解决了问题!

3 只能在堆上创建对象的类

使用使用的类,就不能让用户,可以显式调用到构造函数,不然就在栈区创建了对象!我们需要写出一个接口,让用户可以获取到堆上的对象地址!这样就涉及到了先有鸡先有蛋的问题了,所以我们要将这个接口设置成静态成员函数,才能正常调用!

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方法来释放空间,来完善在堆上创建对象的操作!

4 只能在栈上创建对象的类

同上将构造函数私有化,然后设计静态方法创建对象返回.注意为了防止在堆上创建对象,我们需要将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;

};

5 不能被继承的类

回顾一下继承的知识:从零开始认识继承

不能被继承的类很简单!C++98是将构造函数进行私有化,在C++11之后直接使用final关键字就可以了!

class A final

{

// ....

};

总结

C++的世界里,一些特别的类真是挺有讲究的。就像游戏里的独门魔法宝物,模拟豪华游艇的细节,还有银行系统里那些用完就丢的密码,每一个都是针对特定情况精心设计的。那些不能复制的类,就像是在说“我是特别的,不能随便复制”;只能在堆上或者栈上创建对象的类,就像是给内存管理上了把锁,保证了东西放在该放的地方;而不让继承的类,就像是定了规矩,让功能保持原汁原味。

这些设计不仅展示了C++的强大,也让我们看到程序员先辈们是如何巧妙地解决难题的。通过这几个特殊的类,我们的代码能力肯定有许多长进,C++的学习过程也变得更加丰富多彩了!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。