zoukankan      html  css  js  c++  java
  • [你必须知道的.NET] 第四回:后来居上:class和struct

    本文将介绍以下内容:

    面向 对象基本概念

    类和 结构体简介

    引用 类型和值类型区别

    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)定义接口

        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)测试结构和类


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

    4.2 .NET研究

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

    5. 结论

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

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

    • struct还主要应用在哪些方面?
    •  C++和C#中, 关于struct的应用又有所不同,这些不同又有哪些区别?
  • 相关阅读:
    streamsets 集成 cratedb 测试
    streamsets k8s 部署试用
    streamsets rest api 转换 graphql
    StreamSets sdc rpc 测试
    StreamSets 相关文章
    StreamSets 多线程 Pipelines
    StreamSets SDC RPC Pipelines说明
    StreamSets 管理 SDC Edge上的pipeline
    StreamSets 部署 Pipelines 到 SDC Edge
    StreamSets 设计Edge pipeline
  • 原文地址:https://www.cnblogs.com/top5/p/1665185.html
Copyright © 2011-2022 走看看