基础系列(7)—— 结构

一 结构的定义

       结构用 struct 关键字定义的,与类相似,都表示可以包含数据成员和函数成员的数据结构。数据成员主要包括常量、变量、构造函数、方法、属性等。同时结构的特征为: 结构是一种值类型,并且不需要堆分配。 结构的实例化可以不使用 new 运算符。可以看做是“轻量级的类”

  (1)定义结构的语法:

<访问修饰符> struct 结构名
{
//结构体
}   

  (2)什么时候使用结构

   结构体适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主例如:struct类型适于表示PointRectangle和Color等轻量对象。尽管可以将一个点表示为类,但在某些情况下,使用结构更有效。如果声明一个10000个Point对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。定义的时候不会用到面向对象的一些特性;结构体在不发生装箱拆箱的情况下性能比类类型是高很多的.

    在结构声明中,除非字段被声明为 const 或 static,否则无法初始化赋值。 结构类型永远不是抽象的,并且始终是隐式密封的,因此在结构声明中不允许使用abstract和sealed修饰符结构不能声明默认构造函数(没有参数的构造函数)或析构函数,但可以声明带参数的构造函数。 结构可以实现接口,但不能从另一个结构或类继承,而且不能作为一个类的基,所有结构都直接继承自System.ValueType,后者继承自 System.Object。 结构在赋值时进行复制。 将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。 在使用值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。 结构类型的变量直接包含了该结构的数据,而类类型的变量所包含的只是对相应数据的一个引用(被引用的数据称为“对象”)。但是结构仍可以通过ref和out参数引用方式传递给函数成员。 结构可用作可以为 null 的类型,因而可向其赋 null 值。 

struct Simple
    {
        //public int x = 0; //结构中不能对字段进行初始化
        public int x;
        public int y;
        //public Simple()   //报错,结构中不能使用无参数的构造函数
        //{ 
        //}
    }

    class Csimple
    {
        public int x;
        public int y;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Csimple cs1 = new Csimple(),cs2=null; //类的实例
            Simple ss1 = new Simple(), ss2=new Simple(); //结构的实例
            cs1.x = ss1.x = 5;
            cs1.y = ss1.y = 10;
            cs2 = cs1;
            ss2 = ss1;
        }
    }

   类和变量的实例在赋值前后的栈区和堆区的比较

二 结构的装箱与拆箱

      由于结构不是引用类型,当结构类型的值被转换为object 类型或由该结构实现的接口类型时,就会执行一次装箱操作。 反之,当 object 类型的值或接口类型的值被转换回结构类型时,会执行一次拆箱操作。 与对类类型进行的相同操作相比,主要区别在于: 装箱操作会把相关的结构值复制为已被装箱的实例,而拆箱则会从已被装箱的实例中复制出一个结构值。 因此,在装箱或拆箱操作后,对“箱”外的结构进行的更改不会影响已被装箱的结构。关注于装箱与拆箱的详解讲解,请看:http://www.cnblogs.com/wyh19941210/p/5847086.html

struct Program
{
  static void Main(string[] args)
  {
   int i = 1;object o = i; //隐式装箱
   i = 123;
   Console.WriteLine("i={0},o={1}",i,o);
   Console.Read();
   }
}//结果为:i=123,o=1

 三 结构与构造函数

       我们知道结构不能使用默认的构造函数,只能使用带参数的构造函数,当定义带参数的构造函数时,一定要完成结构所有字段的初始化,如果没有完成所有字段的初始化,编译时会发生错误。 结构可以使用静态构造函数吗? 可以,结构的静态构造函数与类的静态构造函数所遵循的规则大体相同。 结构的静态构造函数何时将触发呢? 结构的实例成员被引用,结构的静态成员被引用,结构显示声明的构造函数被调用。 但是创建结构类型的默认值不会触发静态构造函数。

    为什么结构不能自定义无参数的构造函数? 结构类型的构造函数与类的构造函数类似,用来初始化结构的成员变量,但是struct不能包含显式默认构造函数, 因为编译器将自动提供一个构造函数,此构造函数将结构中的每个字段初始化为默认值表中显示的默认值。 然而,只有当结构用new实例化时,才会调用此默认构造函数。对值类型调用默认构造函数不是必需的。

struct A
{
    static A()
    {
      Console.WriteLine("I am A.");
    }
    public void Fun()
    {

    }
}
 
class Program
{
  static void Main(string[] args)
  {
  A a=new A();
  a.Fun(); //结构的实例成员被引用Console.Read();
  }
}
结果为:I am A.

四  结构与继承

        一个结构声明可以指定实现的接口列表,但是不能指定基类。 由于结构不支持类与结构的继承,所以结构成员的声明可访问性不能是 protected 或 protected internal。 结构中的函数成员不能是 abstract 或 virtual,因而 override 修饰符只适用于重写从 System.ValueType 继承的方法。 为在设计编程语言时将结构设计成无继承性? 其实类的继承是有相当的成本的 ——由于继承性,每个类需要用额外的数据空间来存储“继承图”来表示类的传承历史, 通俗地说来就是我们人类的家族家谱,里面存储着我们的祖宗十八代,只有这样我们才知道我们从哪里来的,而家谱肯定是需要额外的空间来存放的。 大家不要觉得这个存放“继承图”的空间很小,如果我们的程序需要用10000个点(Point)来存放游戏中的人物形体数据的话, 在一个场景中又有N个人,这个内存开销可不是小数目了。所以我们可以通过将点(Point)申明成 Struct而不是class来节约内存空间。

interface ITest
{
void Fun(int x,int y);
}
struct A:ITest
{
   public void Fun(int x,int y) //隐式实现接口里的方法
   {
   Console.WriteLine("x={0},y={1}", x, y);
  }
}

class Program
{
   static void Main(string[] args)
   {
     A a; //结构的实例化可以不使用new
     a.Fun(1, 2);
     Console.Read();
   }
}
// 结果为:x=1,y=2

 五 结构与类的关系

相同点:

   二者实际上都是创建对象的模板,都可以包含构造函数、常量、字段、方法、属性、索引器和运算符等成员

不同点:

(1)结构是值类型,类是引用类型在内存中结构是存储在栈取的值类型,类是存储在堆区的引用类型

(2)结构和类的构造函数不同,结构中不能包含无参数的构造函数,结构成员会自动初始化为它们默认值

(3)结构不能对实例字段成员进行初始化

(4)结构不能继承,就是一个结构不能从另外一个结构或者类中继承,而且不能作为一个类的继承

posted @ 2017-04-08 16:08  StrugglingDave  阅读(1128)  评论(0编辑  收藏  举报