结构不属于面向对象的程序

a struct doesn't belong in an object oriented program

本文关键字:程序 面向对象的 不属于 结构      更新时间:2023-10-16

还是这样?

如果有一个同样有用的结构可以正确地隐藏数据成员,那么面向对象的设计是否应该使用默认情况下公开成员数据的语言结构?

编辑:其中一个响应者提到,如果没有不变量,就可以使用结构。这是一个有趣的观察结果:结构是一个数据结构,即它包含相关的数据。如果一个结构中的数据成员是相关的,不是总是有一个不变量吗?

在C++中,structs和classes除了其成员的默认公共/私有性之外是相同的。(这个默认值很容易,而且通常会被覆盖。)

然而,大多数程序员认为结构是"数据对象",类是"交互式对象"。这不是一件坏事;事实上应该加以利用。如果某个东西只是一个无生命的数据块(即使它有几个检查器方法),请使用一个结构;当程序员试图了解它的用途时,它会节省一些精力。

不要做一个隐藏的狂热分子。如果你的get/set方法什么也不做,只是简单地将值逐字复制到隐藏的私有字段上/从中复制,那么你对公共成员没有任何好处,只会使你的类不必要地复杂化(而且,根据编译器的智能,它的使用速度会稍微慢一点)。

当您的setter方法进行一些验证、将数据复制到其他地方、在存储之前对其进行一点处理等时,有一种情况是不允许直接访问的。同样的情况是getter实际上计算从多个内部源返回的值,并隐藏其导出方式(我相信Bertrand Meyer在他的书中谈到了这一点)

或者,如果允许类的用户直接更改这样的值会产生意想不到的副作用,或者打破某些成员类对这些值的假设。在这种情况下,一定要隐藏你的价值观。

例如,对于一个简单的"Point"类,它只包含几个坐标和颜色,以及在屏幕上"Plot"answers"Hide"的方法,我认为不允许用户直接设置其字段的值是没有意义的。

例如,在C#中,我使用structs来表示一些简单的更好的左值数据类型:

public struct Point
{
    int X;
    int Y;
}

对于任何参数为结构的p/Invoke库,您都必须使用它们。

它们属于应用程序的总体设计吗?当然,在有意义的时候使用结构。就像在有意义时使用带位标志的枚举一样,而不是为了存储组合值而使用一些复杂的字符串解析。

在C++中,结构和类之间的区别在于其内容的默认可见性(即结构的public和类的private)。我想这个区别是为了保持C的兼容性。

但从语义上讲,我想这还需要解释。

结构体示例

在结构中,所有内容都是公共的(默认情况下),这意味着用户可以根据需要修改每个数据值,并且结构仍然是一个有效的对象。结构示例:

struct CPoint
{
   int x ;
   int y ;
   CPoint() : x(0), y(0) {}
   int getDistanceFromOrigin() const
   {
      return std::sqrt(x * x + y * y) ;
   }
} ;
inline CPoint operator + (const CPoint & lhs, const CPoint & rhs)
{
   CPoint r(lhs) ;
   r.x += rhs.x ;
   r.y += rhs.y ;
   return r ;
}

您可以更改CPoint的x值,它仍然是一个有效的CPoint。

注意,与一些人认为的不同,C++结构可以(也应该)在其接口上附加构造函数、方法和非成员函数,如上所示。

课堂示例

在类中,所有内容都是私有的(默认情况下),这意味着用户只能通过定义良好的接口修改数据,因为类必须保持其内部有效。类别示例:

class CString
{
   public :
      CString(const char * p) { /* etc. */ } ;
      CString(const CString & p) { /* etc. */ } ;
      const char *     getString() const { return this->m_pString ; }
      size_t           getSize() const { return this->m_iSize ; }
      void             copy { /* code for string copy */ }
      void             concat { /* code for string concatenation */ }
   private :
      size_t           m_iSize ;
      char *           m_pString ;
} ;
inline CString operator + (const CString & lhs, const CString & rhs)
{
   CString r(lhs) ;
   r.concat(rhs) ;
   return r ;
}

您可以看到,当您调用concat时,指针可能需要重新分配(以增加其大小),并且字符串的大小必须自动更新。您不能让用户手动修改字符串,而忘记更新大小。

因此,类必须保护其内部,并确保在需要时正确更新所有内容。

结论

对我来说,结构和类之间的区别在于聚合数据之间的依赖关系。

如果每一条数据都独立于其他数据,那么也许您应该考虑一个结构(即,具有公共数据成员的类)。

如果没有,或者有疑问,请使用类。

当然,在C#中,结构和类是两种不同类型的对象(即结构的值类型和类的引用类型)。但我想这不属于这个话题。

从技术上讲,结构是一个默认可见性为public的类(真实类的默认可见性为private)。

在通用中还有更多的区别。

结构通常只是数据的集合,由其他代码进行检查和处理。

类通常更像是一个东西,对其数据保持某种控制,并具有由相关函数指定的行为。

通常,类更有用,但偶尔也会有类似C结构的用途,并且通过符号差异来显示它是很有用的。

这很容易。如果class确实有不变量需要保证,那么永远不应该将约束不变量的成员公开。

如果你的struct只是不同对象的集合,并且没有不变量,那么你确实可以自由地将其成员放在public中。C++中的std::pair<T, U>就是这样做的

不变的东西是什么

简单示例:假设您有一个Point类,其x and y成员必须始终是>= 0。你可以做一个不变量陈述

对于此类的对象,
/*x>=0&&y>=0*/

如果您现在公开这些成员,客户端可以简单地更改x和y,并且您的不变量很容易被破坏。然而,如果允许成员包含所有可能的值,这些值分别适合他们自己的不变量,那么你当然可以将这些成员公开:无论如何,你都不会为它们添加任何保护。

结构本质上是一个模型类,但具有不同的语法。

public struct Point {
    int x;
    int y;
}

在逻辑上与相同

public class Point {
    private int x;
    private int y;
    public void setX(int x) { this.x=x; }
    public int getX(); { return x; }
    public void setY(int y) { this.y=y; }
    public int getY(); { return y; }
}

两者都是一个可变模型,包含一对称为x和y的整数值。所以我认为这是一个有效的面向对象构造。

是。这就像一个迷你班。

是的。它们与类具有不同的语义。结构通常被视为值类型,而类通常被视作为引用类型。在每天的节目中,这种差异并没有发音那么多;然而,在封送、COM互操作和传递实例等方面,这是一个重要的区别。

我经常使用structs,主要用于从网络或硬件接收的数据。它们通常封装在一个类中,供程序的更高级别部分使用。

我的经验法则是,结构总是纯数据,构造函数除外。其他任何东西都是一门课。

大多数答案似乎都支持将结构作为可接受和有用的东西,只要它没有行为(即方法)。这似乎很公平。

然而,您永远无法确保您的对象不会演变成可能需要行为的东西,从而对其数据成员进行一些控制。如果您足够幸运,能够控制结构的所有用户,则可以查看所有数据成员的所有使用情况。但是,如果您不能访问所有用户,该怎么办?

结构,如在C或C++中使用的,以及在C#(或任何.Net语言)中使用的结构,是如此不同的动物,它们甚至可能不应该有相同的名称。。。在一种语言中,几乎任何关于结构的概括都很容易是错误的,或者在另一种语言由于完全无关的原因而是正确的。

如果需要不变量,则将其作为一个类。否则,struct是可以的。

请参阅以下类似问题:

在C++中,什么时候应该使用类与结构?

C++中的结构和类之间有什么区别

加:

根据C++程序设计语言中的Stroustrup:

你使用哪种风格取决于环境和品味。我通常更喜欢将struct用于公开所有数据的类。我认为这样的类"不是很合适的类型,只是数据结构。"

形式上,在C++中,结构是一个默认情况下其成员可见性设置为public的类。按照传统,结构用于对同质数据的集合进行分组,这些数据没有特定的理由被特定的方法访问。其成员的公共可见性使structs优先于类来实现策略类元函数

使用结构本身没有错,但如果你发现自己需要它们,你应该问问你的分析出了什么问题。考虑一下上面的Point类:它在可读性方面有一些小的改进,因为你总是可以使用

Point foo;
//...
foo.x = bar;

代替中的双元件阵列

#define X 0
#define Y 1
//...
foo[X] = bar;

但类是为了隐藏合同背后的细节。如果您的Point位于某个标准化空间中,则值的范围可能在半开区间[0.0..1.0)内;如果是屏幕,则其范围可能在[0..1023]内。如果您使用结构代替访问器,则当x应位于< 1.0的所有位置时,如何阻止某人分配foo.x = 1023

C++程序员使用结构表示Points的唯一原因是,早在20年前,当C++还是一个新事物时,内联处理得不太好,所以foo.setX(1023)实际上比foo.x = 1023占用了更多的指令。现在已经不是这样了。

只要保持较小,结构就可以。正如您可能知道的,它们是在堆栈(而不是堆)上分配的,因此您需要注意大小。它们可以在Point、Size等小型数据结构中派上用场。不过,类通常是更好的选择,因为它是引用类型等等。