• 3/类与结构区别


     

    C#结构和类的六点区别

     

    引言··· 1

    区别一:存储类型··· 3

    堆和栈:··· 3

    结构和类的存储类型:··· 3

    区别二:继承性··· 4

    区别三:初始化··· 5

    区别四:构造函数··· 5

    区别五:析构函数··· 7

    区别六:关键字··· 7

    类和结构的使用选择:··· 7

    参考:··· 8

    1、一览表:··· 8

    2、结构和类的区别:··· 8

    3、结构和类的异同:··· 8

    4、源代码:··· 8

    Struct,cs· 8

    Class.cs· 10

    Program.cs· 13

     

    引言

           我们先来看一个例子:

     

     

                                                     例1:类和结构的基本定义

           上面的两个图片一个定义的是类,另一个是结构的定义。从表面上来看,两中数据类型的定义基本没什么区别,类里面有的成员结构都能有,事实上也确实如此。在c#中,两者在本质上都属于数据结构,封装着一组整体作为一个逻辑单位的数据和行为。 数据和行为是该类或结构的“成员”,它们包含各自的方法、属性和事件等(本主题后面列出了这些内容)。结构和类有很大的相似性:

    1、  都是container类型,这表示它们可以包含其他数据类型作为成员。他们可以包含的内容基本相同:字段、构造函数、方法、属性、常量、事件、索引器、运算符、嵌套类型等;

    2、  成员都可以分为静态和非静态,成员的类型、访问方式可以互不相同;

    3、  方法(或称函数)都可以进行重载、复写等操作;

    4、  都派生于System.Object;

    5、   结构定义函数和类中定义函数完全相同;

    6、  都能进行封装;

    7、  都能响应接口;

    8、  都可以通过泛型定义;

    9、  都可以声明和触发事件,而且两者都可以声明委托(Delegate);

    10、              方法或成员的调用方式、对象的初始化都相同;

    11、              默认情况下所有的字段、方法都是私有的

    结构与类在语法上有着很大的相似,但是两者也存在着很明显的区别,具体表现在下面六个方面:

    区别一:存储类型

    堆和栈:

    “栈”(stack)和“堆”(heap)这两个词来源于“运行时”(runtime)对内存进行组织的方式:

         栈内存就像一系列堆叠越高的箱子。调用方法时,它的每个参数都被放入一个箱子,并将这个箱子放到栈的最顶部。每个局部变量也同样分配到一个箱子,并同样放到栈的最顶部。方法结束之后,方法的所有箱子都会从栈中移除。

         堆内存则像散布在房间里的一大堆箱子,而不像栈那样,每个箱子都严格地叠置在另一个箱子上方。每个箱子都有一个标签,它标记了这个箱子是否正在使用。创建一个新对象时,“运行时”会查找一个空箱子,并把它分配给对象。对对象的引用则存储在栈上的一个局部变量中。“运行时”将跟踪每个箱子的引用数量(记住,两个变量可能引用同一个对象)。一旦最后一个引用消失,运行时就将箱子标记为“未使用”。将来某个时候,会清除箱子里的东西,使之能真正重用。

    结构和类的存储类型:

           结构是值类型数据,存储在栈(stack)中。结构进行数据复制的时候,是将原来数据进行备份。创建结构时,结构赋值到的变量保存该结构的实际数据。 将结构赋给新变量时,将复制该结构。 因此,新变量和原始变量包含同一数据的两个不同的副本。 对一个副本的更改不影响另一个副本。

           如:对例1中定义的结构作如下操作:

                  //   使用结构

            static void UseStruct()

            {

                Date labourDay = new Date(5, 1);

                Date yaoMingBirth = labourDay;

                labourDay.ReadDate();

                yaoMingBirth.ReadDate();

                yaoMingBirth.Change(1980, 11, 8);

                labourDay.ReadDate();

                yaoMingBirth.ReadDate();

            }

        显示结果:修改其中一个变量的值,不会影响和它同一个拷贝的另外一个变量。

        

           类是引用类型数据,存储在堆(heap)中和栈(stack)中,堆中存储的是真实的数据,栈中存储的是数据在堆中的地址。就像是在仓库里面放苹果,我们把放苹果的箱子编号,再将编号记录在一个本子上面,这个本子就是栈,仓库就是堆。 

           如:对例1中定义的类进行如下操作:

             //   使用类

            static void UseClass()

            {

                Birthday myBirth = new Birthday(1987, 6, 12);

                Birthday liliBirth = myBirth;

                myBirth.ReadDate();

                liliBirth.ReadDate();

                myBirth.Change(1990, 3, 16);

                myBirth.ReadDate();

                liliBirth.ReadDate();

     

            }

        显示结果:修改一个引用的值,另一个相同的引用的值就会发生改变。

        

    区别二:继承性

           大家都知道,类是可以继承的,它可以继承其他的;类或者接口,也可以被继承,并且,类的许多特性是通过继承来展现的,要阻止类的继承,必须显示的声明sealed。

    结构没有继承:它不能继承另一个结构或者类,也不能被继承。也正因为如此,结构不能有抽象成员。虽然结构没有明确的用sealed声明,可是结构是隐式的sealed

    但是,结构能够继承接口,方法和类继承接口是一样的:

    例如:结构实现接口

      interface IImage

            {

                void Paint();

            }

     

            struct Picture : IImage

            {

                public void Paint()

                {

                    // painting code goes here

                }

                private int x, y, z; // other struct members

            }  

      

    区别三:初始化

           类可以声明的时候就初始化。如:

           class Birthday

        {

            int year;

            byte month;

            byte day;

            int count = 5;

    }

    但是同样的语句用到struct结构中就会发生错误,因为结构中不能在声明一个变量的时候就初始化:

    注意,结构在声明全局变量的时候是可以在声明时就初始化的

    区别四:构造函数

    类和结构都有自己的默认构造函数(默认构造函数不带参数),也都可以编写自己的带参数的构造函数,编写的方法都一样:构造函数没有返回值,并且名称与类(或者结构相同)。但是他们是有区别的:

    在类中,一旦我们编写了带参数构造函数,默认构造函数就不存在了。当我们要调用不带参数的构造函数来初始化对象时,我们必须再自己编写一个不带参数的构造函数。

    如:例1 中类Birthday的构造函数:

    //   构造函数:0在日期中是没有意义的,用来表示用户没有输入

            public Birthday(int yy, byte mm, byte dd)

            {

                this.year = yy;

                this.month = mm;

                this.day = dd;

            }

            public Birthday(int yy, byte mm)

                : this(yy, mm, 0)

            {

            }

            public Birthday(int yy)

            {

                this.year = yy;

         }

    但是在结构中,始终存在一个不带参数的默认构造函数,并且,这个构造函数是不可替代的,不能重写,也不能覆盖,所以,下面操作是错误的:

    public override Date()

            {

                this.year = 1987;

                this.month = 6;

                this.day = 12;

        }

    在结构中,我们只能编写带参数的构造函数,不能编写不带参数的构造函数。

    在类中,声明构造函数的时候我们可以不用初始化所有的字段,系统的(runtime机制)会将我们忽略的字段自动初始化为该类型的零值(0,null,true)

    如,类birthday:我们用构造函数:

    public Birthday(int yy)

            {

                this.year = yy;

         }

    声明一个对象,系统会自动将月日初始化为0,显示的时候就只有年。

    但是在结构中,我们自己编写的构造函数必须显式的为结构的所有字段赋值,否则会发生编译错误。例如,我们将构造函数稍微改动一下:

    public Date(byte mm, byte dd)           

            {

                this.month = mm;

                this.day = dd;

        }

    编译运行不会成功,显示错误: Field 'StructAndClass.Date.year' must be fully assigned before control is returned to the caller

    区别五:析构函数

           类有析构函数,我们都知道,但是结构是没有析构函数的。

           假如我们为结构Date添加析构方法:

           ~Date()

            {

                Console.WriteLine("谁说结构没有析构方法?");

                Console.ReadKey();

            }

        编译会弹出错误:

        Only class types can contain destructors

    区别六:关键字

    1、在类中可以使用但是在结构中限制使用的关键字有:abstract、sealed、protected;

    2、Static关键字可以用在类名前面用来声明静态类,但是不能用在struct前面,不存在静态结构。

    类和结构的使用选择:

    类通常用于对较为复杂的行为建模,或对要在创建类对象后进行修改的数据建模。结构最适合一些小型数据结构,这些数据结构包 含的数据以创建结构后不修改的数据为主。

    何时该用struct、何时该用class:

    1、  大多数情况下该类型只是一些数据时,该类型的行为类似于基于类型,结构式最佳的选择,否则用class

    2、  在表示抽象或者多层次的数据的时候,类是最好的选择:

    3、  该类型不要继承自任何类型,否则用class

    4、  该类型不要继承自任何类型,否则用class

    5、  该类型的实例不会频繁地用于方法的参数传递,否则用class

    6、  该类型的实例不会被频繁地用于诸如ArrayList、Hashtable之类的集合中,否则用class struct表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存,在此情况下,结构的成本较低;当struct变得很大时,应该用class:堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些。

    参考:

    1、一览表:

    2、结构和类的区别:

    http://msdn.microsoft.com/zh-cn/library/ms173109.aspx

    3、结构和类的异同:

    http://hi.baidu.com/loveastyy/blog/item/f15601e8eb771938b80e2da1.html

    4、源代码:

    Struct,cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

     

    namespace StructAndClass

    {

        struct Date

        {

            int year;

            byte month;

            byte day;

     

            //   构造函数

            public Date(int yy, byte mm, byte dd)

            {

                this.year = yy;

                this.month = mm;

                this.day = dd;

            }

            public Date(byte mm, byte dd)           

            {

                //   0年是没有意义的,用来做节日的标记

                this.year = 0;

                this.month = mm;

                this.day = dd;

            }

            public Date(int yy)

                : this(yy, 1, 1)

            {

            }

          

     

            //   读取日期时间

            public void ReadDate()

            {

                if (this.year == 0)

                {

                    Console.WriteLine("{0}-{1}", this.month, this.day);

                }

                else

                {

                    Console.WriteLine("{0}-{1}-{2}", this.year, this.month, this.day);

                }

            }

     

            //   修改日期时间

            public void Change(int yy, byte mm, byte dd)

            {

                this.year = yy;

                this.month = mm;

                this.day = dd;

            }

            public void Change(byte mm, byte dd)

            {

                Change(0, mm, dd);

            }

           

     

            //   重写ToString()方法

            public override string ToString()

            {

                string s = null;

                if (this.year == 0)

                {

                    Console.WriteLine("{0}-{1}", this.month, this.day);

                    s = this.month.ToString() + "-" + this.day.ToString();

                }

                else

                {

                    Console.WriteLine("{0}-{1}-{2}", this.year, this.month, this.day);

                    s = this.year.ToString() + "-" + this.month.ToString() + "-" + this.day.ToString();

                }

                return s;

            }

        }

    }

    Class.cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

     

    namespace StructAndClass

    {

        class Birthday

        {

            int year;

            byte month;

            byte day;

     

            //   构造函数:0在日期中是没有意义的,用来表示用户没有输入

            public Birthday(int yy, byte mm, byte dd)

            {

                this.year = yy;

                this.month = mm;

                this.day = dd;

            }

            public Birthday(int yy, byte mm)

                : this(yy, mm, 0)

            {

            }

            public Birthday(int yy)

            {

                this.year = yy;

            }

     

            ~Birthday()

            {

                Console.WriteLine("没有任何争议,类是有析构方法的!");

                Console.ReadKey();

            }

     

            //   读取生日时间

            public void ReadDate()

            {

                if (this.month == 0)

                {

                    Console.WriteLine("{0}", this.year);

                }

                else if (this.day == 0)

                {

                    Console.WriteLine("{0}-{1}", this.year, this.month);

                }

                else

                {

                    Console.WriteLine("{0}-{1}-{2}", this.year, this.month, this.day);

                }

            }

     

            //   修改生日时间

            public void Change(int yy,byte mm,byte dd)

            {

                this.year = yy;

                this.month = mm;

                this.day = dd;

            }

            public void Change(int yy, byte mm)

            {

                Change(yy, mm, 0);

            }

            public void Change(int yy)

            {

                Change(yy, 0, 0);

            }

      

     

            //   重写ToString()方法

            public override string ToString()

            {

                string s = null;

                if (this.month == 0)

                {

                    Console.WriteLine("{0}", this.year);

                    s = this.year.ToString();

                }

                else if (this.day == 0)

                {

                    Console.WriteLine("{0}-{1}", this.year, this.month);

                    s = this.year.ToString() + "-" + this.month.ToString();

                }

                else

                {

                    Console.WriteLine("{0}-{1}-{2}", this.year, this.month, this.day);

                    s = this.year.ToString() + "-" + this.month.ToString() + "-" + this.day.ToString();

                }

                return s;

            }

        }

    }

    Program.cs

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

     

    namespace StructAndClass

    {

        class Program

        {

     

            //   使用结构

            static void UseStruct()

            {

                Date labourDay = new Date(5, 1);

                Date yaoMingBirth = labourDay;

                labourDay.ReadDate();

                yaoMingBirth.ReadDate();

                yaoMingBirth.Change(1980, 11, 8);

                labourDay.ReadDate();

                yaoMingBirth.ReadDate();

               

     

            }

     

     

            //   使用类

            static void UseClass()

            {

                Birthday myBirth = new Birthday(1987, 6, 12);

                Birthday liliBirth = myBirth;

                myBirth.ReadDate();

                liliBirth.ReadDate();

                myBirth.Change(1990, 3, 16);

                myBirth.ReadDate();

                liliBirth.ReadDate();

     

                Birthday bird = new Birthday(1988);

                bird.ReadDate();

     

            }

     

           

     

            //   程序入口

            static void Main(string[] args)

            {

                UseClass();

                UseStruct();

                Console.ReadKey();

            }

        }

    }

  • 相关阅读:
    汇编-实验9
    Starling开源手势库AcheGesture
    Robotlegs2的Starling扩展
    Flash Builder 4.6/4.7 注释以及字体大小修改
    js中函数的理解
    js对象引用赋值后
    var声明提前 undefined
    光棍节程序员闯关秀
    body和普通div背景图宽高百分比的区别
    笔试题
  • 原文地址:https://www.cnblogs.com/azzhang/p/4215194.html
Copyright © 2020-2023  润新知