第三章 C语言基础.docx
- 文档编号:27942950
- 上传时间:2023-07-06
- 格式:DOCX
- 页数:19
- 大小:30.24KB
第三章 C语言基础.docx
《第三章 C语言基础.docx》由会员分享,可在线阅读,更多相关《第三章 C语言基础.docx(19页珍藏版)》请在冰豆网上搜索。
第三章C语言基础
第三章C#语言基础
C#语言结合和已有计算机编程语言和软件的优点:
VisualC++,VisualBasic,Delphi,C++Builder,JBuilder,Java等。
3.1NGWSRuntime技术基础
3.1.1NGWSRuntime技术简介
用C#语言编写的源程序,必须用C#语言编译器将C#语言源程序编译为中间语言代码(受管制代码,受NGWSRuntime管制),不需要链接,形成扩展名为exe或dll文件。
中间语言代码不是CPU可执行的机器码,中间语言代码必须由NGWSRuntime将中间语言代码翻译为CPU可执行的机器码,由CPU执行。
因此NGWSRuntime为C#语言中间语言代码运行提供了一种运行时环境。
它和Basic语言执行方法类似,但也不完全相同,Basic语言是解释执行Basic语言源程序,其方法是逐句将Basic语言源程序翻译为CPU可执行的机器码。
而C#语言是用NGWSRuntime中的既时编译器将中间语言代码翻译为CPU可执行的机器码,执行速度比Basic快。
在这点上C#语言和JAVA语言基本相同。
这种执行方法使运行速度变慢,但带来其它一些好处,主要有:
●交叉语言集成:
.NET系统包括如下语言:
C#、C++、VB、J#。
所有这些语言的源程序,都编译为相同的中间语言代码,由NGWSRuntime负责执行。
●自动内存管理:
NGWSRuntime内建垃圾收集器,当对象或变量的生命周期结束时,垃圾收集器负责收回不被使用的对象或变量占用的存储空间。
不必象C++语言,用new语句建立的对象,必须用delete语句释放对象占用的存储空间。
也就是说,NGWSRuntime具有自动内存管理功能。
●交叉语言异常处理:
由于所有语言的源程序,都编译为相同的中间语言代码,由NGWSRuntime负责执行,因此异常处理方法是一致的。
这在调试一种语言调用另一种语言的子程序时,显得特别方便。
●增加安全:
C#语言不支持指针,一切对内存的访问都必须通过对象的事例变量来实现,只允许访问内存中允许访问的部分,这就防止病毒程序使用非法指针访问私有成员。
也避免指针的误操作产生的错误。
NGWSRuntime执行中间语言代码前,要对中间语言代码的安全性,完整性进行验证,防止病毒对中间语言代码的修改。
●版本支持:
C#是以组件为基础的编程语言,组件可能要升级,由此可能带来一系列问题,有可能使用旧组件可以运行,使用新组件就运行不了,而新组件可能是安装其它程序时自动替换的。
NGWSRuntime解决了这个问题。
●组件交互简化模式:
采用NGWSRuntime运行环境,使用不同语言设计的组件,可以互相通用,可以从其它语言定义的类派生出本语言的新类。
给使用者带来极大方便。
1.中间语言和元数据
用C#语言编写的源程序,必须用C#语言编译器将C#语言源程序编译为中间语言代码(受管制代码,受NGWSRuntime管制)。
中间语言代码不是CPU可执行的机器码,必须用NGWSRuntime中的既时编译器将中间语言代码翻译为CPU可执行的机器码,由CPU执行。
用C#语言编译器将C#语言源程序编译后,不但包括中间语言代码,还包括元数据。
元数据是类型库、注册表及其它一些中间语言代码运行所需信息。
中间语言和元数据共同包含在C#可执行文件或.dll文件中。
2.既时编译器
既时编译器负责将中间语言代码翻译为CPU可执行的机器码,由CPU区执行。
3.1.2虚拟对象系统(VOS)
虚拟对象系统(VOSVisualObjectSystem)是NGWSRuntime构架的基础,主要由4部分组成:
●类型系统
.NET系统包括如下语言:
C#、C++、VB、J#。
.NET跨语言集成的特性来自于虚拟对象系统VOS的支持。
在不同语言间进行代码复用和应用集成中所遇到的最大问题是不同语言类型系统间的相容性问题。
可以想象不同的语言虽然语法结构大体相同,但数据类型与语言环境本身的各种特点联系紧密,很难想象一种解释性的语言所拥有的数据类型会与一种编译语言相同,而即使相同的数据类型在不同的语言环境中表示的意义也存在差别,例如同样是整数类型,在MSSQL中的长度是32位,而在VB中却是16位,至于日期时间与字符串类型在这方面的区别就更加明显了。
VOS的建立就是为了改变这种状况,它既支持过程性语言也支持面向对象的语言,同时提供了一个类型丰富的系统来容纳它所支持的各种语言的特性,它在最大程度上屏蔽了不同语言类型系统间的转换,使程序员能够随心所欲地选择自己喜欢的语言(当然,这种语言必须支持.NET应用)从事开发,保证了不同语言间的集成。
对于过程性语言,它描述了值的类型并指定了类型的所有值必须遵守的规则。
在面向对象的语言方面它统一了不同编程语言的对象模型。
每一个对象在VOS中都被唯一标识以与其它对象相区别。
●元数据
元数据是类型库、注册表及其它一些中间语言代码运行所需信息。
中间语言和元数据共同包含在C#可执行文件或.dll文件中。
元数据与使用的语言无关,换句话讲,不同语言产生的元数据相同。
●通用语言规范(CLS)
通用语言规范(CommonLanguageSpecificationCLS)是VOS系统中定义的语言特性,所有VOS中的语言都必须遵从通用语言规范,以使不同语言所编译的对象能够相互理解。
一种语言,如遵守通用语言规范,它建立的类库可以被其它语言使用。
●虚拟执行系统(VESVisualExecutionSystem)
虚拟执行系统主要完成以下功能:
(1)装入中间代码。
(2)使用JIT将中间代码转换为本地机器码。
(3)装入元数据。
(4)代码管理服务包括垃圾收集器和异常处理。
(5)定制与调试服务。
(6)线程和环境管理。
●.Net框架的优点:
可以使用任何编程语言,减少编写代码量,以XML/SOAP为核心,提高了应用程序的可靠性,性能更加优化。
.Net通过将各种语言先编译成中间语言(IL),然后再执行即时(JustInTime,JIT)编译器将其编译成本地代码来实现异构平台下对象的互操作。
.Net通过CLR来实现资源对象和类型的安全。
.Net通过HTTP,XML,SOAP,WSDL等Internet标准的支持提供在异构网络环境下获取远程服务、连接远程设备和交互远程应用的编程界面。
.Net的受管代码是指符合CLR进行规范,在内存中受运行时代码代理进行内存管理、线程管理、远程管理、代码强制安全类型的代码。
非受管代码指对内存、文件、数据库等非受管资源进行操作的代码,通常不受运行时代码代理管理,是不安全的。
C#的弱点:
CLS包括MSIL的共享语言基础,只让RAD开发者受益,而损害了硬件的核心开发者。
usingSystem;
classWelcome
{
/*解释开始
解释结束*/
staticvoidMain(){//解释
Console.WriteLine("Pleaseenteryourname:
");
Console.ReadLine();
Console.WriteLine("Welcometoyou!
");
}
}
您可以在任意一种编辑软件中完成上述代码的编写,然后把文件存盘,假设文件名叫做Welcome.cs,典型的C#源文件通常都是以.cs作为文件的扩展名。
例如存到D:
\asp文件夹中。
和C++语言相同,C#语言是大小写敏感的。
高级语言总是依赖于许多在程序外部预定义的变量和函数。
在C或C++中这些定义一般放到头文件中,用#include语句来导入这个头文件。
而在C#语言中使用usingSystem表示导入名字空间,C#中的usingSystem语句的用途与C++中#include语句的用途基本类似,用于导入预定义的变量和函数,这样在自己的程序中就可以自由地使用这些变量和函数。
如果没有导入名字空间的话我们该怎么办呢?
程序还能保持正确吗?
答案是肯定的,那样的话我们就必须把代码改写成下面的样子:
classWelcome
{
staticvoidMain(){
System.Console.WriteLine("Pleaseenteryourname:
");
System.Console.ReadLine();
System.Console.WriteLine("Welcometoyou!
");
}
}
C#中抛弃了C和C++中繁杂且极易出错的操作符像:
:
和->等,C#中的复合名字一律通过.来连接。
System是.Net平台框架提供的最基本的名字空间之一,
C#程序中每个变量或函数都必须属于一个类,不能象C或C++那样建立全局变量。
主函数Main()也必须在一个类中。
程序所完成的输入输出功能是通过Console来完成的,Console是在名字空间中System中已经定义好的一个类。
类Console有两个最基本的方法WriteLine和ReadLine。
ReadLine表示接受输入设备输入,WriteLine则用于在输出设备上输出。
如果您不具备这个条件,那么至少需要安装Microsoft.NetFrameworkSDK,这样才能够运行C#语言程序。
实际上.Net平台内置了C#的编译器,下面让我们使用这个微软提供的命令行编译器对我们的程序进行编译。
3.2C#的变量和类型
C#语言把变量分为数值类型和引用类型。
3.2.1数值类型
C#语言中数值类型可以分为以下几种:
●简单类型(Simpletypes)
●结构类型(Structtypes)
●枚举类型(Enumerationtypes)
1.结构类型
结构类型和类一样,可以声明构造函数、数据成员、方法、属性等,和类的最根本的区别是结构类型是数值类型,类是引用类型。
结构类型的实例一定在堆栈中,类的实例对象一定在堆中。
下面的例子包含了一个命名为IP的简单结构:
usingSystem;
structIP
{publicbyteb1,b2,b3,b4;}//也可以声明构造函数、数据成员、方法、属性等
classTest
{
publicstaticvoidMain()
{
IPmyIP;//未调用构造函数,必须自己初始化数据成员,变量在堆栈中。
MyIP.b1=166;
MyIP.b2=111;
MyIP.b3=171;
MyIP.b4=89;
Console.WriteLine("{0}.{1}",MyIP.b1,MyIP.b2);
Console.WriteLine("{0}.{1}",MyIP.b3,MyIP.b4);
IPYourIP;
YourIP=myIP;//值传递
//使YourIP.b1=166,YourIP.b2=111,YourIP.b3=171,YourIP.b4=89
IPHisIP=newIP();
//用new生成的变量仍在堆栈中,调用默认构造函数,使b1=b2=b3=b4=0。
}
}
2.简单类型
简单类型也是结构类型,是一种简单的结构类型,但不能派生新的结构类型。
因此,它有构造函数、数据成员、方法、属性等,因此:
语句inti=int.MaxValue;strings=i.ToString();是正确的。
即使一个常量,C#也会生成结构类型的实例,应此也可以使用结构类型的方法:
例如:
strings=123.ToString();是正确的。
简单类型包括:
整数类型、字符类型、布尔类型、浮点数类型、十进制类型。
简单类型使用方法和C、C++中相应的数据类型基本一致。
3-1整数类型
整数类型包括:
sbyte、byte、short、ushort、int、uint、long和ulong。
整数类型的使用方法和C++中的使用方法基本一致。
整数类型取值范围为:
sbyte有符号8位整数在-128到127之间
byte无符号8位整数在0到255之间
short有符号16位整数在-32,768到32,767之间
ushort无符号16位整数在0到65,535之间
int有符号32位整数在-2,147,483,648到2,147,483,647之间
uint无符号32位整数0到4,294,967,295之间
long有符号64位整数在9,223,372,036,854,775,808和9,223,372,036,854,775,807之间
ulong无符号64位整数0和18,446,744,073,709,551,615之间
3-2字符类型(char)
需要注意的是,整数类型不能隐式被转换为字符类型(char),例如charc1=10是错误的,必须写成:
charc1=(char)10,charc='A',charc='\x0032';charc='\u0032'。
4.布尔类型(bool)
布尔类型有两个值:
false,true。
不能认为整数0是false,其它值是true。
boolx=1是错误的,不存在这种写法只能写成x=true或x=false。
5.浮点数类型
浮点数类型又包括:
float、double,浮点数类型取值范围为:
单精度:
取值范围在正负1.5⋅10-45到3.4⋅1038之间,精度为7位数。
双精度:
取值范围在正负5.0⋅10-324到1.7⋅10308之间,精度为15到16位数。
1.十进制类型
十进制类型也是浮点数类型,只是精度比较高,一般用于财政金融计算。
十进制类型取值范围为:
取值范围在正负1.0⋅10-28到7.9⋅1028之间,精度为28到29位数
2.枚举类型
使用方法和C、C++中相应的枚举类型基本一致。
3.默认的构造函数
所有的数值类型的实例都要求必须有初值,可以显示的赋值,例如:
inti=0。
而对于复杂结构类型,其中的每个数据成员都按此种方法赋值,显得过于麻烦。
由于数值类型都是结构类型,可用new语句调用其构造函数初始化数值类型实例,例如:
intj=newint()。
请注意,用new语句并不是把int变量放到堆中,仅仅是调用其构造函数。
所有的数值类型都有默认的无参数的构造函数,其功能就是为该数值类型赋初值为默认值。
对于简单类型,sbyte、byte、short、ushort、int、uint、long和ulong默认值为0,char类型默认值是(char)0,float为0.0f,double为0.0d,decimal为0.0m,bool为false,枚举类型为0,结构类型其数据成员中的数值类型设置为默认值,引用类型设置为null。
对于结构类型,由于已有默认的无参数的构造函数,不能再定义无参数的构造函数,但可以定义有参数的构造函数,见书中的例子,还可参见3.3.8节中的例子。
3.2.2引用类型
C#中的另一大数据类型是引用类型,引用这个词在这里的含义是该类型的变量不直接存储所包含的值,而是指向它所要存储的值,也就是说引用类型存储实际数据的引用值的地址。
C#中的引用类型有六种:
●对象类型(object类型)
●类类型
●接口
●代表元
●字符串类型
●数组
1.对象类型
对象类型(object类型)是所有其它类型的基类,C#中的所有类型都直接或间接地从object类中继承。
因此,对一个object的变量可以赋予任何类型的值:
intx=25;
objectobj1;
obj1=x;
objectobj2=‘A’;
对object类型的变量声明采用object关键字,这个关键字是在.Net框架结构为我们提供的预定义的名字空间System中定义的,是类System.Object的别名。
2.类类型
类是面向对象编程的基本单位,是一种包含数据成员、函数成员和嵌套类型的数据结构。
类的数据成员有常量、域和事件。
函数成员包括方法、属性、索引指示器、运算符、构造函数和析构函数。
类和结构同样都包含了自己的成员,但它们之间最主要的区别在于:
类是引用类型,而结构是值类型。
类支持继承机制,通过继承,派生类可以扩展基类的数据成员和函数方法,进而达到代码重用和设计重用的目的。
但和C++不同,C#语言中的仅类允许单继承。
有关类的概念将放在后面详细讲解。
3.接口
C#使用组件进行程序设计。
组件的英文名为component,也称为元件。
组件本质上也是类。
编程者要调用组件的方法改变组件的属性和行为。
为了使编程者都能使用这些组件,组件应提供这些方法的说明,编程者并不关心方法是如何实现的,仅感兴趣方法的类型,名称和参数。
对组件中方法的类型,名称和参数的说明可以放在组件的接口中。
组件的接口一旦被发布,组件生产者就应该尽可能地保持接口不变,任何对接口语法或语义上的改变,都有可能造成现有程序不能运行。
如果组件生产者希望为组件增加功能,只能保留旧接口,定义新的接口,现有程序可以继续使用旧接口,新编制的程序可以使用新接口。
因此,接口给组件使用者提供了组件中的方法的类型、参数类型及个数,即组件方法的使用方法。
接口给组件设计者提供了组件中应实现的方法的类型、参数类型及个数。
●接口声明
接口声明实际上就是一种定义新的接口的类型声明,在接口中,是方法声明的集合。
例如,下面的例子定义了一个名为IControl的接口,接口中包含一个成员方法Paint声明。
interfaceIControl
{voidPaint();}//不能包含实现
在接口的声明体中,可以定义接口的成员。
接口的成员可以是方法、属性、索引指示器和事件。
可使用修饰符new、public、protected、internal、private对接口进行修饰。
在一个接口定义中同一修饰符不允许出现多次,new修饰符只能出现在嵌套接口。
修饰符Public,protected,internal和private定义了对接口的访问权限。
●接口的继承
类似于类的继承性,接口也可以继承和发展。
但接口继承和类继承不同,首先类继承不仅是说明继承,而且也是实现继承,而接口继承只是说明继承,也就是说派生类可以继承基类的方法实现,而派生的接口只继承了父接口的成员方法说明。
其次C#中类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口。
接口可以从零或多个接口中继承。
从多个接口中继承时,用”:
”后跟被继承的接口名字,多个接口名之间用”,”分割。
被继承的接口应该是可以访问得到的,比如从private类型或internal类型的接口中继承就是不允许的。
接口不允许直接或间接地从自身继承。
和类的继承相似,接口的继承也形成接口之间的层次结构。
请看下面的例子:
usingSystem;
interfaceIControl
{
voidPaint();
}
interfaceITextBox:
Icontrol//继承了接口Icontrol的方法Paint()
{
voidSetText(stringtext);
}
interfaceIListBox:
IControl//继承了接口Icontrol的方法Paint()
{
voidSetItems(string[]items);
}
interfaceIComboBox:
ITextBox,IListBox{}
//接口IComboBox继承了方法Paint(),SetText(),SetItems()三个方法
对一个接口的继承也就继承了接口的所有成员,上面的例子中,接口ITextBox和IListBox都从接口IControl中继承,也就继承了接口IControl的Paint方法。
接口IComboBox从接口ITextBox和IListBox中继承,因此它应该继承了接口ITextBox的SetText方法和IListBox的SetItems方法,还有IControl的Paint方法。
●接口成员的种类
接口可以包含一个和多个成员,这些成员可以是方法、属性、索引指示器和事件,但不能是常量、域、操作符、构造函数或析构函数,而且不能包含任何静态成员。
下面例子中接口IExample包含了索引指示器、事件E、方法F、属性P这些成员:
interfaceIExample
{
stringthis[intindex]{get;set;}//索引指示器
eventEventHandlerE;//事件
voidF(intvalue);//方法
stringP{get;set;}//属性
}
publicdelegatevoidEventHandler(objectsender,EventArgse);
接口成员默认访问方式是public。
接口成员声明不能包含任何修饰符,比如成员声明前不能加abstract,public,protected,internal,private,virtual,override或static修饰符。
接口的成员之间不能相互同名。
继承而来的成员不用再声明,但接口可以定义与继承而来的成员同名的成员,这时我们说接口成员覆盖了继承而来的成员,这不会导致错误,但编译器会给出一个警告。
关闭警告提示的方式是在成员声明前加上一个new关键字。
但如果没有覆盖父接口中的成员,使用new关键字会导致编译器发出警告。
●类对接口的实现
前面我们已经说过,接口定义不包括方法的实现部分。
接口中的方法可以通过类或结构来实现。
我们主要讲述通过类来实现接口。
用类来实现接口时,接口的名称必须包含在类声明中的基类列表中。
下面的例子给出了由类来实现接口的例子。
其中ISequence为一个队列接口,提供了向队列尾部添加对象的成员方法Add()。
IRing为一个循环表接口,提供了向环中插入对象的方法Insert(objectobj),方法返回插入的位置。
类RingSquence实现了接口ISequence和接口Iring。
usingSystem;
interfaceISequence
{
objectAdd();
}
interfaceIRing
{
intInsert(objectobj);
}
classRingSequence:
ISequence,IRing
{
publicobjectAdd(){…}
publicintInsert(objectobj){…}
}
如果类实现了某个接口,类也隐式地继承了该接口的所有父接口,不管这些父接口有没有在类声明的基类表中列出。
usingSystem;
interfaceIControl
{
voidPaint();
}
interfaceITextBox:
IControl
{
voidSetText(stringtext);
}
classTextBox:
ITextBox
{
publicvoidPaint(){…}
publicvoidSetText(stringtext){…}
}
这里,类TextBox不仅实现了接口ItextBox,还实现了接口ITextBox的父接口Icontrol。
前面我们已经看到,一个类可以实现多个接口。
再看下面的例子:
usingSystem;
interfaceIControl
{
voidPaint();
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三章 C语言基础 第三 语言 基础