当前位置:   article > 正文

C++类型自定义,什么时候用 struct ,什么时候用 class ?_为什么c++中要用struct而不用class

为什么c++中要用struct而不用class

问:

最近在看深度探索c++对象模型,见到一句“什么时候应该在c++程序中以struct替代class”,对于这个场景很好奇,目前只能想到是对C做出妥协的场景,比如POD,其他的呢?详细的呢?

提问者:先先先 

南老师答:

单从语法角度看, struct 和 class 就两点不同:一是在未指定访问权限的情况下,struct的成员的默认为 public;二是在继承时如不指定继承的访问权限,struct (作为派生者),默认采用 public 方式派生,而 class 默认采用 private 方式。

第一点很常见,第二个点看个例子:

  1. struct D : Base // 未指定 ,相当于 : public Base
  2. {
  3. };

提问者可能更想知道语义上,什么时候用 struct 替代 class ?

这点我完全 推荐 C++ 之父 Bjarne Stroustrup 和 C++标准委员会主席 Herb Stutter 共同主笔写的

C++ 核心指南 的 这一条

C.2: Use class if the class has an invariant; use struct if the data members can vary independently

硬译:

如果这个类有一个“不变式”,那就用 "class" 呗,如果 成员数据 一个个都挺独立的,就用 struct 吧。

显然,重点是 “invariant / 不变式” 。

我的书《白话 C++》,花了很大篇幅,讲解 我们在设计 class 的前前中中后后,要如何识别出这个类的“不变式”。下面从书里抄点简单的例子过来——

例子:对比特定坐标和靶子的类型定义

比如,你写个用于数学坐标计算的简单的小工具,需要用到一个二维坐标点的表达:

  1. struct Point
  2. {
  3. int x, y;
  4. };

假设,你写的这个程序已知就是给你读初一的大儿子用的,因引,你并没有去做深入的需求调研,你就自己定了:int 的取值范围够这小子用的了。

所以,这时候,几乎可以说 这个 Point 类型 不存在“invariant / 不变式”。非要强说有,那就是:这个坐标 的 x轴 和 y轴,都不能超过 int 可表达的范围。 这个“不变式”是由 内置类型 int 来维护的,我们全部的设计责任或成果就是:我选择了 int ,所以我很英明 ,或很愚蠢,如果后面发现初中生竟然需要计算超大值的坐标的时候。

很快,你读幼儿园的二儿子会玩电脑了,于是你给他写了一个 射击游戏程序,里面会有大大小小的靶子(圆形),这时候,如果还使用struct,那么它似乎比Point的定义还要简单:

  1. struct Target
  2. {
  3. int r; // 半径
  4. };

但这个设计就很不对劲了。因为 靶子,哪怕就是给幼儿园小宝宝“瞄准”的靶子,它也是有“不变式 / invariant”的。这个不变式对应着一个产品需求点,小宝宝没法向你表达,像身为一个靠谱的程序员爸爸(都发第一声,否则会变成程序员的甲方)你应该清楚:靶子不能太小,太小宝宝玩起来会生气;靶子也不能太大,太大宝宝玩起来觉得没劲

幻想一下:我们不仅是靠谱的爸爸,我们更是有创意的爸爸,所以我们很快就会推出 “宝宝玩射击 Pro 付费增强版”(尝试以通过开发儿子智慧为名,向他妈妈申请研发费用);而这个版本最大的卖点,就是靶子会在游戏过程中,随某些因素忽大忽小……现在,我们现有必要在心里默念十遍 Target 类的不变式了:“它的半径无论变多大,不能大于某个最大值;同样,无论变多小,也不能小于某个最小值……”。

明确了类的不变式,这个设计就成功了50%,接下来,就是你家终将上市的游戏企业的核心价值了:对于一个中国幼儿园中班到大班的娃,这个最大值和最小值应该是多少呢?

我也不知道。就假设 18 和 5 吧。好,接下来的全部努力,就是要如何维护这个不变式了。显然,第一件要做的事,就是修改 struct Target {... };改为:

  1. class Target
  2. {
  3. static constexpr int max_r = 18;
  4. static constexpr int min_r = 5;
  5. public:
  6. int getR() const { return r; }
  7. void setR(int nr)
  8. {
  9. assert(nr >= min_r && nr <= max_r);
  10. this->r = nr;
  11. }
  12. ...
  13. private:
  14. int r;
  15. };

靶子当然还得有 “测试给定位置是否命中”等等方法,但都不是本课重点了。

这就是不变式——它通常源自业务需求。本例子,如果有关 “幼儿射击的靶子不能过大也不能过小” 这个需求是错误的,那对应到我们从中抽象出来的某个 class 的不变式,自然也是错误或不需要的 (请对比上面的 Point 的例子,那个例子刻意制造了一个没什么不变式的例子)。

有些同学有相朴素的想法:一个自定义类型先是很简单,那就用 strcut,并且数据全开放,等以后真的慢慢变复杂了,再考虑重构使用 class ……

问:那什么是“简单”呢?
答:嗯,大概就一开始数据成员很少,数据之间还都没什么很关系,很 “independently”……

这样想是不太对的。Point 有两个成员数据,却可以(按之父和主席说的)用 struct ,Target 就一个成员数据,按理的话,想和哪个数据发生关系都发生不了……但挡不住,Target 的业务需求,在本课设计的语境里,就是要比 Point 复杂。

所以,要多以业务需求为程序设计的源头,如何做到这一点呢?《白话C++》提了四点。

作业

“一个45度角上的直线”,应该如何设计?请说出它的不变式是什么。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/714799
推荐阅读
相关标签
  

闽ICP备14008679号