博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

深入继承 - 抽象类和接口

Posted on 2007-04-11 18:56  天轰穿  阅读(29843)  评论(40编辑  收藏  举报
因为这个视频还没有做完,我想把抽象类和接口全部做完,估计是两级或者三级,因为里面包含对以前学过的知识的一个复习和其他一些小细节,所以不做完就很难得到一个完整的思路,这两点确实是很绕的,如果没有一个完整的思路和一个比较有说服力的演示,确实很难说清楚!

说实在这两个知识点我确实做得很头疼,演示简单了怎么也说不出为什么需要用这个东西,复杂了又很难讲清楚!我实在很郁闷,目前只是把基本的东西做出来了,完整的演示还没有做出来,我想实在不行就搬一套设计模式来讲出为什么需要用吧.

下面是目前已经做了的,我先发布出来,免得跟我一样的急性子门受不了漫长的等待,哈哈,安慰下

上一节呢狠狠的废话了一大盘(我好久没有废话得这样过瘾了,哈哈).
从这节我们就深入继承,不在是28级讲的那么简单的手啊眼啊男人女人什么的. 如果没记错的话,我以前应该说过类同时只能继承一个类. 那这话是否是真的呢,我有骗你没有呢???  哈哈,想知道吗?  继续看后面的教程吧!  提个醒,我这人凡事爱走偏锋,连瞒天过海的事都会做,所以也许我确实骗了你........



首先我们给出抽象类和接口的概念,大家可以把视频暂停下来记录一下.

抽象类:又叫抽象基类(不是鸡肋):他在定义的时候使用 abstract 关键字标记的一般类.他可包含一般类所包含的所有特性,例如,字段,属性,方法,另外他还包含一个很特殊的方法,叫抽象方法(这些方法基本上是没有执行代码的函数标题,而派生于该类的的类就必须提供执行的代码).最可气的是,他不能被实例化,他主要的用在类的定义和部分实现这方面,所以他需要在扩充类中完整的扩充并实现功能.

抽象方法:  当类中的方法在声明的时候加上 abstract 关键字的时候,他就被我们称为抽象方法(洋名字叫  abstract method , 其实偷偷告诉你哈,我最近学了好多英文单词,虽然还是常常读错,但是已经有很大进步了,估计要不了多久就可以在那里大声朗读李白曾经写过的一首英文诗歌了),但是有个很重要的提醒,只有在抽象类和接口中才可以使用抽象方法.

例如 : 下面这个

public abstract class Thc123_Com
{
       public abstract void GoTo();
}

public class Thc123_Net : Thc123_Com
{
      public override  void GoTo()
      {
             //实现上面抽象方法
       }
}



=========================================================================================

在讲接口之前呢我又想跟大家吹下牛, 大家知道我们的组装计算机,即便是那些品牌机他实际上也是来自很多不同的厂商然后组装起来的, 那么这写硬件之间就有一个必然的联系,那就是他们之间一定要有规范的接口,可是就拿我们的主板来说吧,这个CPU,他既可以是赛阳的,也可以是奔腾的,更可以是速龙,闪龙,当然我跟特别非常十分希望再加上一个咱们中国的CPU品牌,这些CPU肯定采用了一些不同的运算方式啊,所以说我们这个接口就还要学会一点(我们常常劝老人的话,他只要在孝顺你,你就别关他那么多的家务事),说得太好了,我们的接口还要做的事就是不管对方是怎么实现的,反正你插到这里面((*&^#@*&^%$%^$$#$)你就要实现具体的功能,至于你怎么实现就不管那么多了.


接口:他呢其实也是一种特殊的抽象类,用 interface 关键字标记,他的定义没有 class 关键字,他可以包含 方法和属性和事件,但是方法也只能是虚拟方法,任何派生于该接口的类就必须提供执行的代码.任何接口成员前面都不能加修饰符.

接口可用的修饰符有 new  ,  public  ,protected  , internal   ,  private  ,但是同一声明中修饰符只能有一个,new关键字只能出现在镶套接口中,表示复写继承来的同名成员.


接口和类一样,可以被继承和发展,但不同的是,类继承不仅说明继承也会实现继承,但是接口继承只是说明继承,通俗的说,派生类可以继承基类的方法实现,而派生接口只是继承父接口的方法说明,却没有继承父接口的实现.

语法:
interface Ibook
{
      string  GetBookName();
}

接口相关知识:

1.声明在接口中的方法,不可以包含方法的内容区块,简单来说就是不能有大括号存在,例如下面
public interface Ibook  
{
      string  GetBookName()
       { }
}

2. 实现接口的类就要这样写

 public class Employee:Ibook , IUser
{

}

3 .  实现接口需要注意的一些东东

(1).实现一个接口就必须完成接口里的所有方法.(就好象谁家有几个女儿,有漂亮的有对不起观众的,我要去娶那个漂亮的,然后人家开口了,小伙子,你要娶我女儿可以,但是你必须把几个女儿全部娶了,否则我会让你后悔一辈子. )

(2).在实现的类中又有几点必须遵循的(我倒,都三重编号了,看来我写的书后期编辑是件很棘手的事)
   ·存取权限必须相同  ;
   ·返回值类型必须相同
   ·方法的名称必须相同
   ·参数必须相同

(3) . 接口内的方法不能用 virtual  关键字申明,更不要设置存取权限.

下面我们继续来看下个例题

另外还有一种呢就是以明确的方式实现接口

简单来说就是方法前面必须加上接口的名称.这个解释起来没有看起来明确,来吧,看这里(怎么听这话有点怪怪的,难道是我思想不健康,按理说我算是生在阳光下,长在花丛中(不过18岁以后我就基本上是成长在一群 花虫 中了),没理由思想会这么XX啊.)



下面针对抽象类和接口做一个详细的对比

抽象类( abstract method  ) 接口 (  interface  )
可以包含实现区块 不能包含实现区块
可以包含抽象方法 不能包含抽象方法
可以包含非public成员 不可以包含非public成员
能继承其他的类,包含非抽象类 能继承其他接口
可以控制版本 无法控制版本
不能被实例化 不能被实例化


virtual:  这个关键字表示当前方法、属性、索引器或事件的抽象实现或虚实现可被任何派生自这个类的扩充类进行复写.
override:  表示当前方法已经改写了基类的同名同参数的方法、属性、索引器或事件的抽象实现或虚实现.



==============================下面是相关的代码=================================
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// 为了演示显得更简单,我从一C#设计模式书中的例题精简了一下
/// 说心理话,做这级教程真的算是把我折磨够了,我总试图用一个简单的例题同时说明
/// 在什么地方用他最合适,该怎么用,可是简单了就感觉不出为什么需要用
/// 复杂了吧,我口才又不佳,感觉说不清楚,把主题都搞偏离了.很郁闷
/// </summary>

public abstract class vehicle
{//首先我们定义一个抽象的汽车基类

    
public int chelun; //车轮
    public float zhongliang;

    
public vehicle(int cl,float zl)
    
{
        chelun 
= cl;
        zhongliang 
= zl;
    }

    
public abstract string GetMore();
    
//定义一个抽象方法
}

public class car : vehicle
{//定义一个轿车类,继承自vehicel ,所以他必须实现父类中的所有抽象方法

    
public int passeng;  //乘客数量

    
public car(int cl, float zl, int p)
        : 
base(cl, zl)
    
{
        chelun 
= cl; 
        zhongliang 
= zl;
        passeng 
= p;
    }


    
public override string GetMore()
    
{
        
//return 他的详细信息 
    }

}

public class Truck : vehicle
{
    
public int passeng; //乘客数量
    public float load;  //载重

    
public Truck(int cl, float zl, int p, float l)
        : 
base(cl, zl)
    
{
        chelun 
= cl;
        zhongliang 
= zl;
        passeng 
= p;
        load 
= l;
    }

    
public override string GetMore()
    
{
        
//return 卡车的全部信息
    }

}


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using I_B;


public partial class demo : System.Web.UI.Page
{
    
protected void Page_Load(object sender, EventArgs e)
    
{
        
////////////////////////////---接 口 一 演 示---////////////////////////
        Book b = new Book("人性的优点");
        lbl_bn.Text 
= GetS(b);        
    }

    
private static string GetS(IBook ib)
    
{//注意到这里,我们给的参数是我们的接口类型
        return ib.BookName;
        
//这里返回的是我们的接口的属性
    }


        
////////////////////////////---接 口 二 演 示---////////////////////////

    
protected void Button1_Click(object sender, EventArgs e)
    
{//接口二的演示
        I_2_L i2 = new I_2_L();
        i2.A 
= 5;
        lbl_i_2.Text 
= i2.Count(24).ToString();
    }

}



using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;


/**
 * 大致演示接口的定义和访问,下面的例题开始详细的演示每个细节
 * 
*/

namespace I_B
{

    
public interface IBook
    
{
        
string BookName get;set;} //声明接口中的属性
        void InsertToDate();        //声明接口中的方法
    }


    
public class Book : IBook
    
//我们声明这样一个类,他继承了接口IBook

        
string bookname;

        
public Book(string bn)
        
{
            bookname 
= bn;
        }


        
/// <summary>
        
/// 实现接口中的BookName属性
        
/// </summary>

        public string BookName
        
{
            
get return bookname; }
            
set { bookname = value; }
        }

        
/// <summary>
        
///  实现接口中声明的方法
        
/// </summary>

        public void InsertToDate()
        
{
            
//将我们的信息写如数据库
        }

    }


}

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;


/**
 * 在这个演示中我们主要说明一个问题,就是如果继承了有父接口的接口,那么也必须实现他全部父接口的方法和属性
 * 这个就是我刚才说娶老婆的哪个问题了,很头大吧
 * *
*/


interface I_2_A     //声明第一个接口
{
    
int A get;set;}   //声明一个属性
}

interface I_2_B     //声明第二个接口
{
    
int Count(int i,int j); //声明一个方法
}

interface I_2_C : I_2_A, I_2_B { }  //声明第三个接口又继承了前两个接口
//什么都没有声明。但是他实际上是继承了前面两个接口的属性和方法。

public class I_2_L : I_2_C  //声明一个类,他继承了I_2_C这个接口
{
    
int a;

    
public int A
    
{
        
get return a; }
        
set { a = value; }
    }

    
public int Count(int i, int j)
    
{
        
return i * j * a;
    }

}




using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/**
 * 外部对接口的访问,如果出现同名的参数或者方法,必须显示的指出他的父接口。
 * 特别是在不清楚具体情况的前提下,最好是做得保守一点。
 * *
*/


public interface I_3_A
{
    
int Count get;set;}
    
int J(int j);
}

public interface I_3_B
{
    
void Count(int i);
    
double J(double j);
}

public interface I_3_C : I_3_A, I_3_B { }

public class I_3_L

    
public void Sum(I_3_C thc)
    
{
        thc.Count();  
//错误,具有二义性
        thc.Count = 1;  //错误,具有二义性
        thc.Count(1);   //错误,具有二义性


        ((I_3_A)thc).Count 
= 1;     //正确
        ((I_3_B)thc).Count(1);

        ((I_3_A)thc).J(
1);
        ((I_3_B)thc).J(
1);
        thc.J(
1.0);
        thc.J(
1);
    }

}

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;


/**
 * 外部类中对多重继承中的成员访问问题
 * 感觉上有点绕,实际上一下想通了其实也就简单了
 * *
*/


public interface I_4_A
{
    
string F(string A);
}

public interface I_4_B : I_4_A
{
    
new string F(string A);
}

public interface I_4_C : I_4_A
{
    
string T();
}


/// <summary>
/// 下面这个接口我们需要注意一下,他继承了B 和 C ,但是这两个有同时继承了 A
/// 不同的是,他们两个接口在内部定义的时候又采取了不同的策略,我们的访问该是如何的呢?
/// </summary>

public interface I_4_D : I_4_B, I_4_C { };

public class I_4_L
{
    
public string Test(I_4_D thc) //接受的参数类型为接口D类型的
    {
        thc.T();    
//这个好理解,他直接调用 C接口的 T方法
        thc.F("B接口的方法");    //这个呢就直接访问的B接口的F方法,虽然A接口也有一个F方法,但是他这里new了,就是说拦截了向上的访问
        ((I_4_A)thc).F("A接口的方法"); //通过明确指定的方法来访问A接口的F方法
        ((I_4_C)thc).F("A接口的方法"); //因为在C接口中并没有复写A接口的F方法,所以还是可以直接访问的
        ((I_4_D)thc).F("B接口的方法"); //同理是访问B接口的F方法,跟我们第二行的直接访问是一个道理
    }

}