C#面向对象高级语法(一)

密封(sealed)类和方法

sealed关键字可以用来修饰类、变量和方法。sealed修饰符放在类之前,就将类声明为密封类,表示该类不能被继承。密封类主要防治意外的派生,同时可以提高程序的运行性能。在非密封类中,如果要防止一个实例成员在子类中被重写,就可以将该成员声明为密封成员,包括密封方法、密封属性、密封索引器等。对于密封方法,它只能用于对基类的虚方法进行重写,并提供具体的实现。所以在密封方法的声名中,sealed修饰符总是和override修饰符同时使用,以防止派生类进一步重写该方法。

比如:

 1 using System;
 2 class A
 3 {
 4     public virtual void F()
 5     {
 6         Console.WriteLine("A.F");
 7     }
 8 
 9     public virtual void G()
10     {
11         Console.WriteLine("A.G");
12     }
13 }
14 
15 class B : A
16 {
17     sealed override public void F()
18     {
19         Console.WriteLine("B.F");
20     }
21 
22     override public void G()
23     {
24         Console.WriteLine("B.G");
25     }
26 }
27 
28 class C : B
29 {
30     override public void G()
31     {
32         Console.WriteLine("C.G");
33     }
34 }

 

类B对于基类A中的两个虚方法均进行了重载,其中,F方法使用了sealed修饰符,成为了一个密封方法。G方法不是密封方法,所以在B类的派生类C中,可以重载G方法,但是不能重载F方法。

 

  1. 访问控制(Access Control)

关键字

说明

public

所有类均可访问

private

只能被它所在的类内部访问

protected

可以被类内和所有子类访问

internal

限定在类所在的程序内

 

  1. 抽象类与抽象方法

    在现实生活中我们发现,一个类的某个或某几个方法是无法具体实现的。例如图形Shape类中的画图draw()方法,当你不知道具体要画什么形状,比如长方形或者三角形时,怎么可能实现一个画形状的方法呢?在C#中,这样的方法叫做抽象方法,一个类如果有一个或多个抽象方法,这个类就叫做抽象类。

    用abstract关键字来修饰一个类时,该类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。

  • 抽象类必须被继承,抽象方法必须被重写。
  • 抽象类不能被直接实例化,因此它一般用作其他类的基类。
  • 抽象方法只须声明,而无须实现。定义了抽象方法的类必定是抽象类。

实例:两个类Circle和Rectangle,计算面积:

class Circle
{
public float r;
Circle(float r)
{
this.r = r; // this指"这个对象"
}
public float Area()
{
return (float)3.14 * r * r;
}
} 

class Rectangle
{
public float width, height;
Rectangle(float w,float h)
{
this.width = w;
this.height = h;
}
public float Area()
{
return width * height;
}
}

  

假设有若干个Circle以及若干个Rectangle,希望计算它们的面积,直截了当的做法是将他们分别放在2个数组中,用两个循环,加上一个加法,但这种方法不是最好的。因为如果还有其他形状,日triangle、ellipse等,上述方法显得"累赘"。希望有一种统一的表示,例如用给一个数组Shape[],接收所有的形状,然后用

1 foreach(Shape shape in sps)
2 {
3     area_total = shape.Area();
4 }

完成调用。这样的话,我们仅需要一个抽象类Shape。

实例如下:

abstract class Shape
{
    public abstract float Area();
}


class Circle : Shape
{
    public float r;
    public Circle(float r)
    {
        this.r = r;
    }
    public override float Area()
    {
        return (float)3.14 * r * r;
    }
}


class Rectangle : Shape
{
    public float width, height;
    public Rectangle(float width, float height)
    {
        this.width = width;
        this.height = height;
    }

    public override float Area()
    {
        return width * height;
    }
}


public class AbstractShapeTest
{
    static void Main(string[] args)
    {

        Shape circle1 = new Circle((float)2.0);
        Shape rectangle1 = new Rectangle((float)3.4, (float)6.8);
        Console.WriteLine("Circle's Area is:", circle1.Area());
        Console.WriteLine("Rectangle's Area is:", rectangle1.Area());

        Console.ReadKey();
    }
}

// output:
// Circle's Area is:12.56
// Rectangle's Area is:23.12

接口(interface)

从本质上讲,接口是一种特殊的抽象类,这种抽象类中指定实现该接口的类必须提供的成员,实现接口的类提供接口成员的实现。那么为什么要使用接口?

  • 通过接口可以实现不相关类的相同行为,而无须考虑这些类之间的层次关系。
  • 通过接口可以指明多个类需要实现的方法。
  • 通过接口可以了解对象的交互界面,而无须了解对象对应的类。

另外,从软件设计的角度来看,我们希望把复杂的应用系统分割为多个模块,每个模块完成独立的功能,模块之间能够协同工作,这样的模块称为组件。组件可以单独开发、编译和测试,把所有的功能结合到一起,就得到了完整的系统。要使组件能够协同工作,就必须在组件之间提供一种工作协议,而接口就非常适合作为组件之间的协议描述工具。

  1. 接口的定义

    接口定义格式如下:

    [接口修饰符] interface 接口名 [:基接口列表]

    {

        // 接口成员

    }

    其中,接口修饰符是可选的,只允许为new修饰符或者访问修饰符public、protected、internal或protected。基接口也是可选的,接口可以从零个或多个接口继承。interface和接口名是必需的,接口名是一种标示符,应符合标示符的命名规则,最好能体现接口的含义和用途。根据命名惯例,接口名总是以大写字母I开头。

    接口成员具有如下要求:

  • 接口成员必须是方法、属性、事件或索引器。接口不能包含常量、字段、运算符和实例构造函数、析构函数或类型,也不能包含类的静态成员。
  • 接口只包含方法、属性、事件或索引器的签名,而不提供他们的实现。
  • 接口成员都是public类型的,但是不能使用public修饰。

下面是接口的一个实例:

1 interface ITest
2 {
3     string Name
4     {
5         get;
6         set;
7     }
8     void MyMethod();
9 }

接口可实现多重继承,即一个接口可以继承多个接口,在冒号后跟上一个由逗号分开的基接口列表,例如:

 1 interface ITest1
 2 {
 3     void M1();
 4 }
 5 
 6 interface ITest2
 7 {
 8     void M2();
 9 }
10 
11 interface ITest3
12 {
13     void M3();
14 }
15 
16 interface ISubTest : ITest1, ITest2, ITest3
17 {
18     //
19 }

ISubTest将多重继承ITest1、ITest2和ITest3,将同时具备方法M1、M2和M3。

  1. 接口的实现

    在类中继承接口叫做对接口的实现(Implementation),例如:

 1 interface Collection
 2 {
 3     //方法是共有的public,C#编译器会自动加上public关键字
 4     void Add(Object obj);
 5     void Delete(Object obj);
 6     Object Find(Object obj);
 7     int CurrentCount();
 8 }
 9 
10 
11 
12 class Queue : Collection
13 {
14     public void Add()
15     {
16         // ...
17     }
18 
19     public void Delete()
20     {
21         // ...
22     }
23 
24     public Object Find(Object obj)
25     {
26         // ...
27     }
28 
29     public int CurrentCount()
30     {
31         // ...
32     }
33 }

再看一个完整的示例,为了演示把之前使用的Shape抽象类变为接口:

 1 interface IShape
 2 {
 3     void Draw();// 不能有任何实现的部分
 4     //{
 5     // System.Console.WriteLine("draw in shape");
 6     //}
 7 }
 8 
 9 class Circle : IShape
10 {
11     private double r;
12     public Circle(double r)
13     {
14         this.r = r;
15     }
16 
17     public void Draw()
18     {
19         Console.WriteLine("draw in circle,r={0}", r);
20     }
21 }
22 
23 class Rectangle : IShape
24 {
25     private double width;
26     private double height;
27 
28     public Rectangle(double width, double height)
29     {
30         this.width = width;
31         this.height = height;
32     }
33 
34     public void Draw()
35     {
36         Console.WriteLine("draw in rectangle,width={0},heigth={1}", width, height);
37     }
38 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值