第4章 在C#中使用类和对象

第4章 在C#中使用类和对象

4.1 关于类

所有的C#程序都由类组成。Windows窗体就是类,它派生于基本的Form类。
我们即将要编写的其他所有程序都是完全由类组成的。
C#没有全局数据或共享数据的概念,因为它们不是类的组成部分。

简单的说,类就是将一系列公有和私有方法以及私有数据组合在一个命名的逻辑单元中。
通常将一个类放在一个单独文件里,尽管这不是硬性的规定。

一个类创建后,它就不仅仅是一个单一实体了,而是一个“模板”,可以用new关键字创建它的副本或实例。
创建实例时,可以用类的构造函数把初始化数据传到类中。
构造函数是与类名相同的方法,没有返回类型,可以有0个或多个传递给类实例的参数。
我们把实例叫做对象。


4.2 一个简单的温度转换程序

摄氏度和华氏度之间转换的小程序

然而该程序是用户界面和数据处理都集中在一个程序模块里,而不是分别进行处理.
通常,把数据处理和界面处理分开是一种好的想法。
这样,修改界面的逻辑不会影机依然。


4.3 构造一个Temperature类


C#中的类是一个模块,它包含公有的和私有的函数与子例程,也包含私有数据.
通常将类中的函数和子例程统称为方法。

类模块把一系列数据放在单独的命名空间中,用取出(get)函数和设置(set)函数存取数据,我们将这两种
方法为访问方法.

我们可以把所有的计算和温标之间的转换都移到新的Temperature类里。
设计该类的一种方式是:先重写使用该类模块的调用程序。
创建一个Temperature类的实例,用它完成转换工作.

实际的类如下所示:
注意这里把输入的温度字符串放到类的构造函数里,它将字符串转换成浮点值.
不必知道数据的内部表示,也能在任何时候改变它.
public class Temperature{
 private float temp,newTemp;
 public Temperature(string thisTemp){
  temp=Convert.ToSingle(thisTemp);
}
 public string getConvTemp(bool celsius){
 if(celsius)
  return getCels();
 else
  return getFahr();
 }
 private string getCels(){
  newTemp=5*(temp-32)/9;
  return newTemp.ToString();
 }
 private string getFahr(){
  newTemp=9*temp/5+32;
  return Convert.ToString(newTemp
);
 }
}
注意,温度变量temp声明为私有的,这样类的外部就不能访问它了.
只能用构造函数和getConvTemp方法存取数据。
这样设计代码的要点是,外部调用程序不必知道数据如何存储,如何取回,这是类内部需要知道的事情.

实际上类可以包含相当复杂的数据,这就是所谓的封装.
很容易修改这个类,来获得其他温标下的温度值,而且还不需要类的用户去了解如何存储数据或如何执行转换等事情。

在这个类中,有公有和私有两种方法。
公有方法可以被其他模块调用,如用户界面窗体模块.
私有方法(getCels和getFahr)在内部使用,对温度变量进行操作.


4.7 类与对象

面向过程的程序设计和面向对象(OO)的程序设计的主要差别在于类的出现。
类只是一个模块,就像我们前面给出的那样,它既包含公有的和私有的方法,也包含数据.
类是惟一的,一个类可以有多个实例,每个实例包含不同的数据。通常把这些实例称为对象,后面我们会看到单个实例和多个实例的例子.

例子:
假设把一场游泳比赛的结果存储在一个文本数据文件里。ID,名字,年龄,俱乐部,时间(成绩);


4.8 类包含

让一个类包含其他类在面向对象的程序设计中很常见,这也是由简单程序构造复杂程序的一种主要方式.


4.9 初始化

在前面的Swimmer类里,它的构造函数接下来调用了StringTokenizer类的构造函数.


public Swimmer(String dataLine){
 StringTokenize tok=new StringTokenizer(dataLine);
}


4.10 类和属性

C#的类拥有属性和方法,还拥有公有,私有函数及子程序.
这些属性相当于Form的各种属性,但它们能存储,取出要使用的各种数据。
例如:下面的代码没有getAge方法和setAge方法,
只有一个Age属性,它相当于get方法和set方法:
private int Age;
public int Age{
 get{
  return Age;
 }
 set{
  Age=value;
 }
}
注意,属性声明在属性名后没有圆括号,专门的关键字value用来获得存储的数据.要使用这些属性:
age=sw.Age //获取属性值
sw.Age=12 //设置属性值


4.12 代理

C#引入了类C语言中的一个独特属性,叫做代理。
代理本质上是对另一个类中的函数的引用,可以分派和使用函数而无需知道它来自哪一个类,只要函数满足同样的接口就可以。

代理是一个类方法的原型,以后会赋给它一个实际的“身份”。
方法即可以是静态的也可以来自某个类实例。
可以将代理声明为一种类型声明。
private delegate string fTxDelegate(string s);
fTxDelegate ftx; //instance of delegate

注意,由类实例创建代理的语法与由静态方法创建代理的语法稍有不同。
ftx=new fTxDelegate(new Capital().fixText); //instance //非静态方法要定义类实例
ftx=new fTxDelegate(Lower.fixText);
//static //静态方法直接调用即可

代理方法可以在编辑时提供更多的灵活性,但她确实不是一个全新的方法,因为可以使用接口并直接通用fixText方法实现同样的功能。


4.13 索引器

C#引入了一种特殊的类方法,叫做索引器。
它可以用某种方法访问类中的数据元素,使该数据看起来像数组元素一样。

public class BitList
{
 private int number;
 public BitList(string snum){
  number=Convert.ToInt32(snum);
}
public int this[int index]
{
 get{
  int val=number>>index;
  return val;
 }
}
}

private void numbericUpDown1_ValueChange(object sender,EventArgs e){
int index=Convert.ToInt32(numericUpDown1.Value);
BitList bits=new BitList(txNum.Text);
int bit=bits[index];
lsBits.Items.Add(Convert.ToString(bit));
}

索引器对类似于数组的引用是很方便的,但是它不提供函数,不如类方法那样容易实现。


4.14 运算符重载

+ - * / % & | ^ << >> == != > < >= <=
可以为任何给定的类重新指定这些运算符的含义.
可以为一个假定的Complex类定义"+"运算符:
public static Complex operator +(Complex c1,Complex c2)
{
 return new Complex(c1.real+c2.real,c1.imaginary+c2.imaginary);
}
这样做会使程序非常难以理解,所以不推荐使用这一特性.


4.15 小结

在本章中介绍了C#类,指出类能够包含公有的和私有的方法,还可以包含数据。
每个类可以有多个实例,每个实例可以包含不同的数据值.类也可以用属性方法设置,取回数据。
属性方法提供了一个比通常的getXxx和setXxx访问方法更简单的语法,但没有其他实质上的优点。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值