.NET技术:.NET中class和struct的区别

日期: 2008-04-20 来源:TechTarget中国

  1、引言


  提起class和struct,我们首先的感觉是语法几乎相同,待遇却天壤之别。历史将接力棒由面向过程编程传到面向对象编程,class和struct也背负着各自的命运前行。在我认为,struct英雄迟暮,class天下独行,最本质的区别是class是引用类型,而struct是值类型,它们在内存中的分配情况有所区别。由此产生的一系列差异性,本文将做以全面讨论。


  2、基本概念


  2.1、什么是class?


  class(类)是面向对象编程的基本概念,是一种自定义数据结构类型,通常包含字段、属性、方法、属性、构造函数、索引器、操作符等。因为是基本的概念,所以不必在此详细描述,读者可以查询相关概念了解。我们重点强调的是.NET中,所有的类都最终继承自System.Object类,因此是一种引用类型,也就是说,new一个类的实例时,对象保存了该实例实际数据的引用地址,而对象的值保存在托管堆(managed heap)中。


  2.2、什么是struct?


  struct(结构)是一种值类型,用于将一组相关的信息变量组织为一个单一的变量实体 。所有的结构都继承自System.ValueType类,因此是一种值类型,也就是说,struct实例分配在线程的堆栈(stack)上,它本身存储了值,而不包含指向该值的指针。所以在使用struct时,我们可以将其当作int、char这样的基本类型类对待。



  图1


  3、相同点,不同点


  相同点:语法类似。


  不同点:


  ◆class是引用类型,继承自System.Object类;struct是值类型,继承自System.ValueType类,因此不具多态性。但是注意,System.ValueType是个引用类型。


  ◆从职能观点来看,class表现为行为;而struct常用于存储数据。


  ◆class支持继承,可以继承自类和接口;而struct没有继承性,struct不能从class继承,也不能作为class的基类,但struct支持接口继承。


  ◆class可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有值初始化为它们的0等价值。


  ◆实例化时,class要使用new关键字;而struct可以不使用new关键字,struct在声明时就进行了初始化过程,所有的成员变量均默认为0或null。


  ◆class可以实抽象类(abstract),可以声明抽象函数;而struct为抽象,也不能声明抽象函数。


  ◆class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和GetHashTable()。


  ◆class的对象复制分为浅拷贝和深拷贝,必须经过特别的方法来完成复制;而struct创建的对象复制简单,可以直接以等号连接即可。


  ◆class实例由垃圾回收机制来保证内存的回收处理;而struct变量使用完后立即自动解除内存分配。


  ◆作为参数传递时,class变量是以按址方式传递;而struct变量是以按值方式传递的。


  我们可以简单的理解,class是一个可以动的机器,有行为,有多态,有继承;而struct就是个零件箱,组合了不同结构的零件。其实,class和struct最本质的区别就在于class是引用类型,内存分配于托管堆;而struct是值类型,内存分配于线程的堆栈上。由此差异,导致了上述所有的不同点,所以只有深刻的理解内存分配的相关内容,才能更好的驾驭。本系列将再以后的内容中,将引用类型和值类型做以深入的比较和探讨,敬请关注。当然正如本文标题描述的一样,使用class基本可以替代struct的任何场合,class后来居上。虽然在某些方面struct有性能方面的优势,但是在面向对象编程里,基本是class横行的天下。


  那么,有人不免会提出,既然class几乎可以完全替代struct来实现所有的功能,那么struct还有存在的必要吗?答案是,至少在以下情况下,鉴于性能上的考虑,我们应该考虑使用struct来代替class:


  ◆实现一个主要用于存储数据的结构时,可以考虑struct。


  ◆struct变量占有堆栈的空间,因此只适用于数据量相对小的场合。


  ◆结构数组具有更高的效率。


  ◆提供某些和非托管代码通信的兼容性。


  所有这些是struct有一席之地的理由,当然也许还有其他的更多说法,只是我不知道罢了。


  4、经典示例


  4.1、小菜一碟


  下面以示例为说明,来阐述本文的基本规则,详细见注释内容。


  (1)定义接口


  interface IPerson
  {


  void GetSex();


  }
 
  (2)定义类


  public class Person
  {


  public Person()


  {


  }


  public Person(string name, int age)


  {


  _name = name;


  _age = age;}


  private string _name;


  public string Name


  {


  get { return _name; }


  set { _name = value; }


  }


  private int _age;


  public int Age


  {


  get { return _age; }


  set { _age = value; }


  }


  }
 
  (3)定义结构


  //可以继承自接口,不可继承类或结构


  struct Family: IPerson
  {


  public string name;


  public int age;


  public bool sex;


  public string country;


  public Person person;


  //不可以包含显式的无参构造函数和析构函数


  public Family(string name, int age, bool sex, string country, Person person)


  {


  this.name = name;


  this.age = age;


  this.sex = sex;


  this.country = country;


  this.person = person;


  }


  //不可以实现protected、virtual、sealed和override成员


  public void GetSex()


  {


  if (sex)


  Console.WriteLine(person.Name + ” is a boy.”);


  else


  Console.WriteLine(person.Name + ” is a girl.”);


  }


  public void ShowPerson()


  {


  Console.WriteLine(“This is {0} from {1}”, new Person(name, 22).Name, country);


  }


  //可以重载ToString虚方法


  public override string ToString()


  {


  return String.Format(“{0} is {1}, {2} from {3}”, person.Name, age, sex ? “Boy” : “Girl”, country);


  }


  }
 
  (4)测试结构和类



  图2


  猜猜运行结果如何,可以顺便检查检查对这个概念的认识。


  4.2、.NET研究


  在.NET框架中,System.Drawing命名空间中的有些元素,如System.Drawing.Point就是实现为struct,而不是class。其原因也正在于以上介绍的各方面的权衡,大家可以就此研究研究,可以体会更多。另外,还有以struct实现的System.Guid。


  5、结论


  对基本概念的把握,是我们进行技术深入探索的必经之路,本系列的主旨也是能够从基本框架中,提供给大家一个通向高级技术的必修课程。本文关于class和struct的讨论就是如此,在.NET框架中,关于class和struct的讨论将涉及到对引用类型和值类型的认识,并且进一步将触角伸向变量内存分配这一高级主题,所以我们有必要来了解其运行机制,把握区别和应用场合,以便在平常的系统设计中把握好对这一概念层次的把握。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐

  • 为什么说Objective-C很难学?

    作为一个网络上的活跃分子,使用Objective-C的开发者,我收到了许多围绕Objective-C的提问。这些问题在人们学习 Objective-C或者尝试开发app的时候会不断跳出来。

  • .NET架构师:函数式语言做领域驱动设计

    Scott一位.NET架构师,同时也是掌握函数式编程的作者,他很欣赏函数式编程,对于Scott来说,面向对象编程的那些概念也很恐怖,比如多态、泛型、继承、协变等。

  • 软件开发就像炒股 关键看你怎么选股票!

    本文作者Paulo Ortins在这里分享了对于选择哪种编程语言作为软件开发工作的起点的话题,并阐述了自己的观点。

  • 增进离岸Java开发效率的十个提示

    近日,Cygnet Infotech公司发布了一篇博文,谈到了如何增进离岸Java开发的效率。众多的ISV与软件厂商总是在不断寻找能以最低的代价实现其业务目标的解决方案。