实验三类与类的封装

实验三 类与类的封装

【实验目的与要求】

? ? ? ? ? ? ? ?

理解面向对象程序设计的思想和基本概念 使用构造函数和析构函数 给类写方法

给一个类增加属性

理解静态方法和实例方法之间的异同 掌握方法的重载

掌握类索引器的编写方式 掌握运算符的重载

【实验内容与步骤】

类是C#语言实现面向对象程序设计的基础,它是C#封装的基本单元,类把对象、属性和方法这些类成员封装在一起构成一个有机的整体,即数据机构。在C#中,类是程序的最核心部分,没有了类,就连简单的C#程序都不能编译。 类是可以包含数据成员(常数和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数)以及嵌套类型的数据结构。类类型支持继承,继承是派生类可用以扩展和专用化基类的机制。 一、类的声明

类的声明就是定义一个新类,其格式如下: [属性] [类修饰符] class 标识符 [:基类] { 类体 };

类声明包含一组可选的属性(C# 使程序员可以创造新的说明性信息种类,称为属性),后跟一组可选的类修饰符

( new;public;protected;internal;private;abstract;sealed ),然后是关键字 class 和一个命名该类的标识符,接着是一个可选的继承基类,最后是可根据需要后接一个分号的类体。 二、类的成员

类的成员包括由它的类成员声明引入的成员和从直接基类继承的成员。

类的成员分为下列几种类别:

1 / 17

常数,表示与类相关联的常数值。 字段,类的变量。

方法,实现可由类执行的计算和操作。

属性,定义与读取和写入这些特性相关的命名特性。 事件,定义可由类生成的通知。

索引器,允许以与索引数组相同的方式索引类的实例。 运算符,定义可以应用于类的实例的表达式运算符。 实例构造函数,实现初始化类的实例所需要的操作。

析构函数,实现在永久性放弃类的实例之前要执行的操作。 静态构造函数,实现初始化类自身所需要的操作。 类型,表示类的局部类型。

可以包含可执行代码的成员被总称为类的函数成员。类的函数成员是该类的方法、属性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数。

类声明创建新的声明空间,而由类声明包含的最近的类成员声明将新成员引入到此声明空间中。下列规则适用于类成员声明:

实例构造函数、静态构造函数和析构函数必须具有与最近的封闭类相同的名称。所有其他成员必须具有与最近封闭类不同的名称。

常数、字段、属性、事件或类型的名称必须不同于在同一个类中声明的所有其他成员的名称。

方法的名称必须不同于在同一个类中声明的所有其他非方法的名称。此外,方法的签名必须不同于在同一个类中声明的所有其他方法的签名。

实例构造函数的签名必须不同于在同一个类中声明的所有其他实例构造函数的签名。

索引器的签名必须不同于在同一个类中声明的所有其他索引器的签名。 运算符的签名必须不同于在同一个类中声明的所有其他运算符的签名。 类的继承成员不是类的声明空间的组成部分。因此,允许派生类用与继承成员相同的名称或签名来声明成员(这实质上隐藏了继承成员)。

三、构造函数与析构函数

在可以访问一个类的方法、属性或任何其它东西之前, 第一条执行的语句是包含有相应类的构造函数。甚至你自己不写一个构造函数,也会有一个缺省的构造函数提供给你。

class TestClass {

public TestClass(): base() {} // 由编译器提供 }

一个构造函数总是和它的类名相同,但是,它没有声明返回类型。总之,构造函数总是public的,你可以用它们来初始化变量。

2 / 17

public TestClass() {

// 在这给变量

// 初始化代码等等。 }

如果类仅包含静态成员(能以类型调用,而不是以实例调用的成员),你可以创建一个private的构造函数。 private TestClass() {}

尽管存取修饰符在这一章的后面将要大篇幅地讨论,但是private意味着从类的外面不可能访问该构造函数。所以,它不能被调用,且没有对象可以自该类定义被实例化。

并不仅限于无参数构造函数——你可以传递初始参数来初始化成员。 public TestClass(string strName, int nAge) { ... }

作为一个C/C++程序员,你可能习惯于给初始化写一个附加的方法,因为在构造函数中没有返回值。当然,尽管在C#中也没有返回值,但你可以引发一个自制的异常,以从构造函数获得返回值。

但是,当你保留引用给宝贵的资源,应该想到写一个方法来解决:一个可以被显式地调用来释放这些资源。问题是当你可以在析构函数(以类名的前面加\的方式命名)中做同样的事情时,为何还要写一个附加的方法. ~TestClass() {

// 清除 }

你应该写一个附加方法的原因是垃圾收集器,它在变量超出范围后并不会立即被调用,而仅当间歇期间或内存条件满足时才被触发。当你锁住资源的时间长于你所计划的时间时,它就会发生。

因此,提供一个显式的释放方式是一个好主意,它同样能从析构函数中调用。 public void Release() {

// 释放所有宝贵的资源 }

~TestClass() {

Release(); }

调用析构函数中的释放方法并不是必要的——总之,垃圾收集会留意释放对象。但没有忘记清除是一种良好的习惯。

3 / 17

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4