码迷,mamicode.com
首页 > Windows程序 > 详细

【C#学习笔记】二、面向对象编程

时间:2015-06-26 09:10:25      阅读:370      评论:0      收藏:0      [点我收藏+]

标签:

2.1 抽象类与接口

1)概念

抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。接口是引用类型的,接口和抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的作为子类去实现,接口和抽象类的相似之处有三点:

²        不能实例化;

²        包含未实现的方法声明;

²        派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);

 

2)抽象类和接口的区别

²        类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为规范或规定

²        接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法

²        一个类一次可以实现若干个接口,但是只能扩展一个父类

²        接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。


3)抽象类和接口的使用:

²        如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本。

²        如果创建的功能将在大范围的全异对象间使用,则使用接口。如果要设计小而简练的功能块,则使用接口。

²        如果要设计大的功能单元,则使用抽象类.如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。   

²        抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。


 以下是我在网上看到的几个形象比喻,真的非常不错,呵呵:
1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。
2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);  

而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。 门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染))。

2.2 接口多态性

假定不使用基类提供EatFood()方法,而是把该方法放到接口IConsume上,Cow和Chicken类也支持这个接口(Cow和Chicken类必须提供EatFood()方法的执行代码),接着就可以使用下述代码访问该方法:

Cow myCow=new Cow();

Chicken myChicken=new Chicken();

IConsume consumeInterface;

consumeInterface=myConw;

consumeInterface.EatFood();

consumeInterface=myChicken;

consumeInterface.EatFood;

2.3 Window应用程序中的OOP(P180)

【例子1】

private void button1_Click(object sender,System.EventArgs e)

{

((CButton)sender).Text=”Clicked!”;  

Button newButton=new Button();

newButton.Text=”New Button!”;

newButton.Click+=new EventHandler(newButton_Click);

Controls.Add(newButton);

}

private void newButton_Click(object sender,System.EventArgs e)

{

    ((Button)sender).Text=”Clicked!”;

}

 技术分享

2.4 类的定义(P184)

C#中只能有一个基类,如果继承了一个抽象类,就必须实现所继承的所有抽象成员(除非派生类也是抽象的)。一个类可指定多个接口,如:

public class MyClass: MyBase, IMyInterface, IMySecondInterface

{

}

修饰符

                          含义

无或internal

类只能在当前项目中访问

public

类可以在任何地方访问

abstract或internal abstract

类只能在当前项目中访问,不能实例化,只能继承

public abstract

类可以在任何地方访问,不能实例化,只能继承

sealed 或internal sealed

类只能在当前项目中访问,不能派生,只能实例化

public sealed

类可以在任何地方访问,不能派生,只能实例化

 

关键字abstract和sealed不能在接口中使用,因为这两个修饰符在接口定义中无意义(接口不包含执行代码,所以不能直接实例化,且必须是可以继承的)。接口可使用多个基接口,如:

public interface IMyInterface: IMyBaseInterface, IMyBaseInterface2

{

}

2.5 构造函数执行顺序(P192)

public class MyBaseClass

{

public MyBaseClass(){}

public MyBaseClass(int i){}

}

public class MyDerivedClass: MyBaseClass

{

public MyDerivedClass(){}

public MyDerivedClass(int i){}

public MyDerivedClass(int i, int j){}

}

 

MyDerivedClass myObj=new MyDerivedClass();

l         执行System.Object.Object()构造函数。

l         执行MyBaseClass.MyBaseClass()构造函数。

l         执行MyDerivedClass.MyDerivedClass()构造函数。

 

MyDerivedClass myObj=new MyDerivedClass(4);

l         执行System.Object.Object()构造函数。

l         执行MyBaseClass.MyBaseClass(int i)构造函数。

l         执行MyDerivedClass.MyDerivedClass(int i)构造函数。

 

MyDerivedClass myObj=new MyDerivedClass(4,8);

l         执行System.Object.Object()构造函数。

l         执行MyBaseClass.MyBaseClass()构造函数。

l         执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数。

 

若MyDerivedClass的定义做如下修改:

public class MyDerivedClass:MyBaseClass

{

….

public MyDerivedClass(int i, int j) : base(i)

{}

}

则MyDerivedClass myObj=new MyDerivedClass(4,8);其执行顺序如下:

l         执行System.Object.Object()构造函数。

l         执行MyBaseClass.MyBaseClass(i)构造函数。

l         执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数。

 

若MyDerivedClass定义作如下修改:

public class MyDerivedClass:MyBaseClass

{

public MyDerivedClass():this(5,6)

{}

public MyDerivedClass(int i, int j) :base(i)

}

则MyDerivedClass myObj=new MyDerivedClass();的执行顺序如下:

l         执行System.Object.Object()构造函数。

l         执行MyBaseClass.MyBaseClass(i)构造函数。

l         执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数。

l         执行MyDerivedClass.MyDerivedClass()构造函数。

2.6 定义类成员(P209)

1)成员修饰符

public:   成员可以由任何代码范围

private:   成员只能由类中的代码访问(如果没有使用任何关键字,就默认使用这个关键字)

internal:  成员只能由定义它的项目(程序集)内部的代码访问

protected: 成员只能由类或派生类中的代码访问

 

2)方法修饰符

static:  只能通过类访问,不能通过对象实例化来访问

abstract: 方法必须在非抽象的派生类中重写(只用于抽象类中)

virtual:  方法可以重写

override: 方法重写了一个基类方法(如果方法被重写,就必须使用该关键字)

extern:   方法定义放在其它地方

 

【例子1】字段、属性与方法

public class MyClass

{

    //使用readonly修饰,只能声明或构造函数中赋值

    public readonly string Name;

private int intVal;

//属性Val的访问器属性为protect所以不能直接在main中使用,但可在其派生类中使用

    public int Val

    {

        protected get

        {

             return intVal+1;

         }

         //不能同时设置两个访问器的权限

         set

         {

             if (value >= 0 && value <= 10)

                 intVal = value;

             else

                 //使用throw抛出异常

throw (new ArgumentOutOfRangeException("Val",value,"Val 必须是0~10"));

         }  

     }

     //重写了Object类的ToString方法,所以要用override修饰符

     public override string ToString()

     {

         return "Name:" + Name + "\nVal:" + Val;

      }

      //使用this关键字调用自身的MyClass(string newName)构造函数

      private MyClass(): this("Default Name"){}

      public MyClass(string newName)

      {

          Name = newName;

          intVal = 0;

       }

}

public class MyClass2 : MyClass

{

     Internal int myVal;

     //构造函数中使用base关键字调用基类的构造函数

     public MyClass2() : base("MyClass2"){}

     //由于基类的Val属性的get访问器修饰符为protected,只能在类或派生类代码中访问

     public int Val

     {

         //派生类代码中可直接使用基类中Val属性的get和set访问器

         get {return base.Val;}

         set {base.Val = value;}

     }

}

 

class Program

{

static void Main(string[] args)

    {

        MyClass2 obj2=new MyClass2();

        Console.WriteLine(obj2.ToString());

        obj2.myVal = 20;

        Console.WriteLine("obj2.myVal={0}", obj2.myVal);

        for (int i = 0; i <= 11; i++)

        {

            obj2.Val = i;

            Console.WriteLine("intVal={0}", obj2.Val);

         }

         Console.ReadKey();

}

}

 技术分享

【例子2】类中的静态字段和静态方法(Ch09Ex03)

 class Program

 {

     static void Main(string[] args)

     {

          //实例化时只能调用非静态函数及非静态字段,类调用时只能调用静态函数和静态字段

          MyExternalClass myClass = new MyExternalClass(2);

          myClass.ShowIntVal();

          MyExternalClass.strName = "My Static Name";

          MyExternalClass.ShowName();

          Console.ReadKey();

      }

 }

public class MyExternalClass

{

private int myIntVal;

    public static string strName;

    public static void ShowName()

    {

        Console.WriteLine(strName);

}

//使用构造函数来为私有变量myIntVal赋值

public MyExternalClass(int nVal)

    {

        myIntVal = nVal;

    }

    public void ShowIntVal()

    {

        Console.WriteLine("MyIntVal={0}", myIntVal);

     }

}

2.7 隐藏基类方法(P219)

class Program

{

    static void Main(string[] args)

    {

        DerivedClass1 C1 = new DerivedClass1();

        DerivedClass2 C2 = new DerivedClass2();

        C1.DoSomething1();

        C2.DoSomething2();

 

        BaseClass C0;

        C0 = C1;

        C0.DoSomething1();   //执行基类的代码,输出 DoSomething1 In Base Class

        C0=C2;

        C0.DoSomething2();   //执行继承类的代码,输出DoSomething2 In DerivedClass2

    }

}

class BaseClass

{

    internal void DoSomething1()

    {

        Console.WriteLine("DoSomething1 In Base Class");

}

//使用virtual修饰,表示方法可以被重写

    virtual internal void DoSomething2()

    {

        Console.WriteLine("DoSomething2 In Base Class");

    }

}

class DerivedClass1 : BaseClass

{

    new internal void DoSomething1()

    {

        Console.WriteLine("DoSomething1 In DerivedClass1");

}

}

class DerivedClass2 : BaseClass

{

    //override会重写基类代码

    internal override void DoSomething2()

    {

        Console.WriteLine("DoSomething2 In DerivedClass2");

    }

}

 技术分享

 

【C#学习笔记】二、面向对象编程

标签:

原文地址:http://www.cnblogs.com/meditatorBlog/p/OOOP.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!