(转载)后来居上:class和struct

你必须知道的.NET] 第四回:后来居上:class和struct-王涛

[你必须知道的.NET]第四回:后来居上:class和struct

Author: 王涛

Date:2007-4-24

©2007 Anytao.com ,原创作品,转贴请注明作者和出处。

本文将介绍以下内容:

  • 面向对象基本概念
  • 类和结构体简介
  • 引用类型和值类型区别

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 这样的基本类型类对待。

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 关键 字,如果不以new 来实例化struct ,则其所有的字段将处于未分配状态,直到所有字段完成初始化,否则引用未赋值的字段会导致编译错误。
  • 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 )定义接口

  1. interface IPerson
  2.     {
  3.         void GetSex();
  4.     }

(2 )定义类

  1. public class Person
  2.     {
  3.         public Person()
  4.         { 
  5.         }
  6.  
  7.         public Person(string name, int age)
  8.         {
  9.             _name = name;
  10.             _age = age;
  11.         }
  12.  
  13.         private string _name;
  14.  
  15.         public string Name
  16.         {
  17.           get { return _name; }
  18.           set { _name = value; }
  19.         }
  20.  
  21.         private int _age;
  22.  
  23.         public int Age
  24.         {
  25.           get { return _age; }
  26.           set { _age = value; }
  27.         } 
  28.     }

(3 )定义结构

  1. //可以继承自接口,不可继承类或结构
  2.     struct Family: IPerson
  3.     {
  4.         public string name;
  5.         public int age;
  6.         public bool sex;
  7.         public string country;
  8.         public Person person;
  9.  
  10.         //不可以包含显式的无参构造函数和析构函数
  11.         public Family(string name, int age, bool sex, string country, Person person)
  12.         {
  13.             this.name = name;
  14.             this.age = age;
  15.             this.sex = sex;
  16.             this.country = country;
  17.             this.person = person;
  18.         }
  19.  
  20.         //不可以实现protected、virtual、sealed和override成员
  21.         public void GetSex()
  22.         {
  23.             if (sex)
  24.                 Console.WriteLine(person.Name + " is a boy.");
  25.             else
  26.                 Console.WriteLine(person.Name + " is a girl.");
  27.         }
  28.  
  29.         public void ShowPerson()
  30.         {
  31.             Console.WriteLine("This is {0} from {1}"new Person(name, 22).Name, country);
  32.         }
  33.  
  34.         //可以重载ToString虚方法
  35.         public override string ToString()
  36.         {
  37.             return String.Format("{0} is {1}, {2} from {3}", person.Name, age, sex ? "Boy" : "Girl", country);
  38.         }
  39.     }

(4 )测试结构和类

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

4.2 .NET 研究

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

5.结论

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

另外,请大家就以下问题进行讨论,希望能够更加清晰本文的拓展:

  •  struct 还主要应用在哪些方面?
  • C++ 和C# 中,关于struct 的应用又有所不同,这些不同又有哪些区别
posted @ 2011-03-09 14:48 一杯浓茶 阅读(...) 评论(...) 编辑 收藏