为什么不直接使用类字段?

时间:2013-11-24 21:22:58

标签: c# c++ class properties

所以我知道类和结构是数据结构。类字段默认为私有字段和结构字段 - 公共字段。就像C ++的public: / int a;和C#的public int a;一样

但访问这些字段的其他方法是使它们私有并使用函数/方法。就像SetValue(int value){a = value;}GetValue() { return a; }一样,或者我甚至听说过C#中的新酷{set; get;}

但是为什么?许多人告诉我'其他人可以通过这种方式访问​​您的变量,因此请将其设为私有'。我不明白,它有什么区别让它们公开,只是使用它们obj.a = 3;或将它们设为私有并且obj.SetValue(3);?有人(甚至可以简要地)解释差异是什么以及s.o.当他们公开时到达那些领域?

8 个答案:

答案 0 :(得分:5)

为什么要使用属性(getter和setter)而不是公共字段(实例变量公开),有很多原因。其中一些是:

  • 您可以允许对外部类进行只读访问(通过提供getter而不是setter)
  • 您可以在访问时计算该值。
  • 您可以在不破坏现有代码的情况下更改访问/计算值的方式。
  • 您可以在不破坏现有代码的情况下更改内部表示。
  • 您可以覆盖子类中的属性,这对于字段是不可能的。

此外,使用属性并没有太多缺点。所以优点胜过缺点。

答案 1 :(得分:2)

不同语言的答案有所不同。

在C ++中,最好将属性设为私有并提供getter和setter方法,因为C ++提供了const正确性 - 并且不能在const对象上调用setter。

在不提供常量正确性的C#中,除了简单地将所有属性提供为公共外,似乎没有意义,因为只要有一个setter它就可以在任何时候被调用。

但是,例如,该属性是一个容器(例如,List)。那么你可能只希望人们能够操作列表而不是将列表指针设置为新值 - 所以你要定义这样的属性:

class Contrived
{
    private List<Things> m_List = new List<Things>();

    public List<Things> LIST{ get {return m_List;} }
};

或者您可能只希望人们能够检查列表,但不能添加或删除其中的内容:

class Contrived
{
    private List<Things> m_List = new List<Things>();

    public IEnumerable<Things> LIST{ get {return m_List;} }
};

通过这种方式,我们通过使用接口来伪装const正确性,尽管IMO并不像只有一个const正确的语言那样好。 ;-)确实,在最后一个例子中,我们提供了一个列表,它不能被修改但是内容可以是,所以我们可以像这样实现这个属性(假设Things实现了IUnmoddableThing):

class Contrived
{
    private List<Things> m_List = new List<Things>();

    public IEnumerable<IUnmoddableThing> LIST{ 
    get 
    {
        List<IUnmoddableThing> temp = new List<IUnmoddableThing>();
        ... copy m_List into temp ...
        return temp;
    } }
};

显然允许我们更多地控制而不仅仅是将成员属性公开。在我们进入一个隐藏事实的地方之前,我们实际上可能......哦,通过套接字连接到远程数据库,由定制的军用无线电承载...

一旦你意识到可以在编译时拒绝使用setter(使用const正确的语言)并且getter / setter或get / set(取决于语言)可以做的不仅仅是分配或返回,它们可以是非常强大。

答案 2 :(得分:1)

这是呼叫封装,允许您正确管理对班级信息的访问:Encapsulation

并不总是需要封装,但强烈建议隐藏您的类内部并防止未经授权的数据管理,例如,您可以向您的setter添加一些检查,如果数据是公开的,则无法阻止:

int SomeClass::setPointer(char *point)
{
   if(!point)
   {
      cout << "Trying to assign null pointer" << endl; //Or, better, throw exception
      return error; // Or, better, throw exception
   }
   mPointer = point;
}

这是最基本的优势,但应该有其他类似的:

  • 每次修改主数据时,您都可以自动更新相关的控制数据(例如,每次添加新元素时的数组大小)。
  • 样式:它更容易维护(例如,你更改成员的类型,你只需要在setter中添加一个强制转换,而不是修改所有调用该字段的行)
  • 提高可用性
  • 在某些情况下,表现更佳。

答案 3 :(得分:1)

范围 - 例如公共和私人是一种告诉人们如何使用你的课程的方法

任何公开(或使用C ++保护)都是与您的班级用户签订合同的一部分

这意味着:

你不应该改变任何公开的

您可以随意更改任何私密内容,因为这被视为您班级的实施细节

答案 4 :(得分:1)

这种行为被广泛认为是“良好的编程方式”,以便始终为类用户提供一个他可以自由使用的界面,而不必担心破坏其中的任何内容。这就是为什么人们应该在类似方法的访问器中关闭更改类属性的原因。当更改字段也会改变其他字段并对类产生影响时,它非常有用。此外,当你试图找到有人正在改变破坏某些东西的字段值时,它会派上用场;)

答案 5 :(得分:1)

那么,如果您想稍后将该属性更改为数据库调用该怎么办?对于一个领域来说这是不可能的。另外,如果您不希望可以从类外部设置属性,而不是在内部,那该怎么办?如果您想要更改它以便仅设置非空值,该怎么办?当值改变时,您能收到通知吗?你不能做任何一个有字段的人,而且所有人都有getter + setter。

答案 6 :(得分:0)

其他答案列出了很多很好的封装理由。我只想补充一个最基本的原因:

  • 保护班级的不变量

如果您的课程旨在保持一定的不变性,则不得向您的课程用户提供任何破坏它的方法。例如,如果您设计容器,则授予用户对capacitysize等内容的写入权限是不明智的。

答案 7 :(得分:-1)

此外,类中数据成员的值很少是独立的,直接访问(更改值)数据很容易使对象处于不一致状态。