zoukankan      html  css  js  c++  java
  • Struct和Class的区别

    C#的struct结构具有以下特点:

    数据类型:结构是值类型,而类是引用类型。
    数据类型:向方法传递结构时,结构是通过传值方式传递的,而不是作为引用传递的。
    实例化:与类不同,结构的实例化可以不使用 new 运算符(未验证)

    位置:结构可以写到class中,与方法并列;也可以写在class外,与类并列。
    构造函数:结构可以声明有参数的构造函数,但它们必须给所有的属性赋值(this.x=xx;this.y=yy;...)。

          若声明无参的构造函数,编译期间报错:编译器错误消息: CS0568: 结构不能包含显式的无参数构造函数
    继承类:一个结构不能从另一个结构或类继承,而且不能作为一个类的基。--即,结构不搞基。
    继承自:所有结构都直接继承自 System.ValueType,后者继承自 System.Object。
    实现接口:结构可以实现接口。

    C#之结构struct(转)

    结构是使用 struct 关键字定义的,与类相似,都表示可以包含数据成员和函数成员的数据结构。 一般情况下,我们很少使用结构,而且很多人也并不建议使用结构,但作为.NET Framework 一般型別系统中的一个基本架构,还是有必要了解一下的。
    结构的特征: 结构是一种值类型,并且不需要堆分配。 结构的实例化可以不使用 new 运算符。
    在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。 结构类型永远不是抽象的,并且始终是隐式密封的,因此在结构声明中不允许使用abstract和sealed修饰符。
    结 构不能声明默认构造函数(没有参数的构造函数)或析构函数,但可以声明带参数的构造函数。 结构可以实现接口,但不能从另一个结构或类继承,而且不能作为一个类的基,所有结构都直接继承自System.ValueType,后者继承 自 System.Object。 结构在赋值时进行复制。 将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。 在使用值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。 结构类型的变量直接包含了该结构的数据,而类类型的变量所包含的只是对相应数据的一个引用(被引用的数据称为“对象”)。但是结构仍可以通过ref和 out参数引用方式传递给函数成员。 结构可用作可以为 null 的类型,因而可向其赋 null 值。

    复制代码
    struct A
    {
    public int x; //不能直接对其进行赋值
    public int y;
    public static string str = null; //静态变量可以初始化
    public A(int x,int y) //带参数的构造函数
    {
    this.x = x;
    this.y = y;
    Console.WriteLine("x={0},y={1},str={2}", x, y,str);
    }
    
    }
    class Program
    {
    static void Main(string[] args)
    {
    A a = new A(1,2);
    A a1 = a;
    a.x = 10;
    Console.WriteLine("a1.x={0}",a1.x);
    Console.Read();
    }
    }
    复制代码

    结果为:x=1,y=2,str=            a1.x=1 此时a1.x值为1是因为,将a赋值给a1是对值进行复制,因此,a1不会受到a.x赋值得改变而改变。

    但如果A是类,这时a和a1里的x引用的是同一个地址,则a1.x的值会输出10。

    结构的装箱与拆箱

    我们知道,一个类类型的值可以转换为 object 类型或由该类实现的接口类型,这只需在编译时把对应的引用当作另一个类型处理即可。 与此类似,一个object 类型的值或者接口类型的值也可以被转换回类类型而不必更改相应的引用。当然,在这种情况下,需要进行运行时类型检查。 由于结构不是引用类型,上述操作对结构类型是以不同的方式实现的。 当结构类型的值被转换为object 类型或由该结构实现的接口类型时,就会执行一次装箱操作。 反之,当 object 类型的值或接口类型的值被转换回结构类型时,会执行一次拆箱操作。 与对类类型进行的相同操作相比,主要区别在于: 装箱操作会把相关的结构值复制为已被装箱的实例,而拆箱则会从已被装箱的实例中复制出一个结构值。 因此,在装箱或拆箱操作后,对“箱”外的结构进行的更改不会影响已被装箱的结构。

    复制代码
    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
    复制代码

     什么情况下结构的实例化可以不使用new?

    当结构中没有参数时,结构的实例化可以不使用new;

    当结构中有参数时,必须对结构中所有参数进行初始化后,才能不使用new对结构进行实例化。

    什么时候使用结构?

    结构体适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主;

    例如:struct类型适于表示Point、Rectangle和Color等轻量对象。

    尽管可以将一个点表示为类,但在某些情况下,使用结构更有效。

    如果声明一个10000个Point对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。­

    定义的时候不会用到面向对象的一些特性;

    结构体在不发生装箱拆箱的情况下性能比类类型是高很多的.

     C++的Struct和Class的区别

    转载来源:http://blog.sina.com.cn/s/blog_48f587a80100k630.html

    C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能。
    struct能包含成员函数吗? 能!
    struct能继承吗? 能!!
    struct能实现多态吗? 能!!!
     

    既然这些它都能实现,那它和class还能有什么区别?

    最本质的一个区别就是默认的访问控制: 

    默认的继承访问权限

    struct是public的,class是private的。
    你可以写如下的代码:
    struct A
    {
      char a;
    };
    struct B : A
    {
      char b;
    };

    这个时候B是public继承A的。

    如果都将上面的struct改成class,那么B是private继承A的。这就是默认的继承访问权限。 

    所以我们在平时写类继承的时候,通常会这样写:
    class B : public A

    就是为了指明是public继承,而不是用默认的private继承。

    当然,到底默认是public继承还是private继承取决于子类而不是基类

    我的意思是,struct可以继承class,同样class也可以继承struct,那么默认的继承访问权限是看子类到底是用的struct还是class。如下:

    struct A{};class B : A{}; //private继承
    struct C : B{}; //public继承

    struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的

    我依旧强调struct是一种数据结构的实现体,虽然它是可以像class一样的用。我依旧将struct里的变量叫数据,class内的变量叫成员,虽然它们并无区别。


    到底是用struct还是class,完全看个人的喜好,你可以将程序里所有的class全部替换成struct,它依旧可以很正常的运行。但我给出的最 好建议,还是:当你觉得你要做的更像是一种数据结构的话,那么用struct,如果你要做的更像是一种对象的话,那么用class。 

    当然,我在这里还要强调一点的就是,对于访问控制,应该在程序里明确的指出,而不是依靠默认,这是一个良好的习惯,也让你的代码更具可读性。 

    说到这里,很多了解的人或许都认为这个话题可以结束了,因为他们知道struct和class的“唯一”区别就是访问控制。很多文献上也确实只提到这一个区别。 

    但我上面却没有用“唯一”,而是说的“最本质”,那是因为,它们确实还有另一个区别,虽然那个区别我们平时可能很少涉及。

    那就是:“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。这一点在Stanley B.Lippman写的Inside the C++ Object Model有过说明。 

    问题讨论到这里,基本上应该可以结束了。但有人曾说过,他还发现过其他的“区别”,那么,让我们来看看,这到底是不是又一个区别。还是上面所说 的,C++中的struct是对C中的struct的扩充,既然是扩充,那么它就要兼容过去C中struct应有的所有特性。例如你可以这样写: 

    struct A //定义一个struct
    {
       char c1;
       int n2;
       double db3;
    };
    A a={'p', 7, 3.1415926}; //定义时直接赋值 

    也就是说struct可以在定义的时候用{}赋初值。那么问题来了,class行不行呢?将上面的struct改成class,试试看。报错!噢~于是那人跳出来说,他又找到了一个区别。我们仔细看看,这真的又是一个区别吗? 

    你试着向上面的struct中加入一个构造函数(或虚函数),你会发现什么?
    对,struct也不能用{}赋初值了
    的确,以{}的方式来赋初值,只是用一个初始化列表来对数据进行按顺序的初始化,如上面如果写成A a={'p',7};则c1,n2被初始化,而db3没有。这样简单的copy操作,只能发生在简单的数据结构上,而不应该放在对象上。加入一个构造函数或是一个虚函数会使struct更体现出一种对象的特性,而使此{}操作不再有效。 

    事实上,是因为加入这样的函数,使得类的内部结构发生了变化。而加入一个普通的成员函数呢?你会发现{}依旧可用。其实你可以将普通的函数理解成对数据结构的一种算法,这并不打破它数据结构的特性。 

    那么,看到这里,我们发现即使是struct想用{}来赋初值,它也必须满足很多的约束条件,这些条件实际上就是让struct更体现出一种数据机构而不是类的特性。 

    那为什么我们在上面仅仅将struct改成class,{}就不能用了呢?

    其实问题恰巧是我们之前所讲的——访问控制!你看看,我们忘记了什么?对,将struct改成class的时候,访问控制由public变为 private了,那当然就不能用{}来赋初值了。加上一个public,你会发现,class也是能用{}的,和struct毫无区别!!! 

    做个总结,从上面的区别,我们可以看出,struct更适合看成是一个数据结构的实现体,class更适合看成是一个对象的实现体。

  • 相关阅读:
    Code First Migrations更新数据库结构(数据迁移) 【转】
    Lambda表达式详解【转】
    @Html.Raw用法
    ASP.NET MVC文件上传【转】
    SQL Server附加数据库拒绝访问错误解决方法
    window.location.href的用法
    vs2013中将复制过来的文件或文件夹显示到解决方案管理
    Expression<Func<TObject, bool>>与Func<TObject, bool>的区别
    VS中的一些标记
    ob_get_contents()
  • 原文地址:https://www.cnblogs.com/joean/p/4609279.html
Copyright © 2011-2022 走看看