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();

}

}

}

时间: 2024-08-10 23:30:08

3/类与结构区别的相关文章

结构体和类的唯一区别就是类函数没有加说明是私有而结构体函数是公有

结构体和类的唯一区别就是              类函数没有加说明是私有                   而   结构体函数是公有

C#:类和结构的区别

第一.引用类型和值类型 类属于引用类型,而结构属于值类型. 结构在赋值时进行复制. 将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据. 第二.继承性 类可以继承类或者实现接口,而结构只能实现接口,不能继承结构. 第三.实例化 类的实例化需要使用new关键字,但是结构的实例化则可以不使用new关键字. 第四.构造函数 类可以显式地包含无参的构造函数,但是结构却不可以显式地包含无参构造函数,只可以定义带有参数的构造函数. 第五.初始化实例字段 类可以在类的定义中

.net 中struct(结构)和class(类)的区别

1.struct 结构与class(类)的区别 1)struct是值类型,class是对象类型 2)struct不能被继承,class可以被继承 3)struct默认访问权限是public,而class默认是private 5) struct不能由程序员申明构造函数,有编辑器自动生成,用于描述轻量级对象,执行效率高,例如:Line,Point等 6)struct的new和class的new是不同的,struct的new就是执行一下构造函数创建一个实例,再对所有字段进行复制. 而class则是在堆

c#中结构体(struct)和类(class)的区别

一.类与结构的示例比较: 结构示例: public struct Person { string Name; int height; int weight public bool overWeight() { //implement something } } 类示例: public class TestTime { int hours; int minutes; int seconds; public void passtime() { //implementation of behavior

类的声明 , 类和结构体的区别 , 内联函数

#include<iostream> using namespace std; class A;//类的声明 class B { private: A *a;//必须是指针 ,不能为 A a; }; class  A { private: B b; }; int main() {} 类和结构体区别: 结构体默认public 类默认是private 在继承方式:结构体默认公有继承 类默认私有继承 inline 调用内联函数并没有执行函数的调用过程,只是把函数的代码嵌入到了程序的调用点 , 减少了

2017年11月4日 vs类和结构的区别&amp;哈希表&amp;队列集合&amp;栈集合&amp;函数

类和结构的区别 类: 类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存 类有构造和析构函数 类可以继承和被继承 结构: 结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象. 结构没有构造函数,但可以添加.结构没有析构函数 结构不可以继承自另一个结构或被继承,但和类一样可以继承自接口 //哈希表 //不规定长度 不规定类型 不规定建类型 //Hashtable j = new Hashtable(); //

Swift类与结构、存储属性、计算属性、函数与方法、附属脚本等

写了12个Person来复习,不过完成同样的代码需要敲键盘的次数相比OC确实少了很多,这很多应该归功于Swift中不写分号,以及少了OC中的中括号. 一.类与结构体 两者在Swift中差不了多少了 类与结构体有很多相同的地方: (第2,3点是其他语言中不存在的) 1)都可以定义属性/方法/下标(结构体也可以定义方法了) 2)都能初始化(通过构造方法) 3)都能使用扩展(extension)与协议(protocol) 4)类与结构体(枚举)中的全局属性/方法:在类中用class关键字,但在结构体中

Swift面向对象基础(上)——Swift中的类和结构体(上)

学习来自<极客学院> 1 import Foundation 2 3 //1.定义类和结构体 4 /* 5 [修饰符]calss 类名{ 6 零到多个构造器 7 零到多个属性 8 零到多个方法 9 零到多个下标 10 } 11 修饰符可以是:private public internal final 12 */ 13 14 /*定义结构体 15 [修饰符]struct 结构体名{ 16 17 } 18 修饰符可以是:private public internal 19 */ 20 21 /*

类与结构体比较

//结构示例: public struct Person { string Name; int height; int weight } public bool overWeight() { //implement something } 类示例: public class TestTime { int hours; int minutes; int seconds; } public void passtime() { //implementation of behavior } } 调用过程