深入继承——抽象类和接口

深入继承——抽象类和接口

 

一、基本概念 

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

抽象方法:  当类中的方法在声明的时候加上 abstract 关键字的时候,称为abstract method ,但是只有在抽象类接口中才可以使用抽象方法

例如 :
public abstract class sun
{
       public abstract void GoTo() ;
}

public class sun1 : sun  //继承基类的类sun1
{
      public override void GoTo()
      {
             //实现上面抽象方法
       }
}

接口其实也是一种特殊的抽象类,用 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 关键字申明,更不要设置存取权限.

 

接口的映射:(interface mapping)

接口成员必须由类来加以实现,那么我们就把在类中定位接口成员的实现称之为接口的映射
映射说白了就是一一对应的关系,什么一一对应呢?我们这里说的是接口的映射,那么肯定就是接口成员类中实现相应的接口成员之间的对应关系了。

【注意事项】
1.接口映射时不但包括他自己的成员,同时也包括了他所有继承接口的成员
2.映射时,显式的实现成员比其他的更有优先权
3.private,protected,static被这些修饰过的成员不能参与接口的实现。


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

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

 

 MSDN的建议是:

  • 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。
  • 如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
  • 如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
  • 如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。


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

 

二、接口的继承相关用法:

(1)接口的定义属性方法事件以及继承类的申明:

public interface Ia

{ string A{ get;set; } //申明接口属性

   void B();         //申明接口方法

  event C Cname;     //申明接口事件

}

public class Sun : Ia  //继承了Ia接口的类Sun

{ public event C Cname; //实现他的事件

  string a;

  public Sun(string b){a=b;}  //类Sun的构造函数

  public string A

    { get{return a;}

      set{a=value;this.Cname(value);}

    }

  public void B() { //具体的B方法 }

}

(2)继承父接口就要继承父接口的所有属性和方法:

interface I_A  {int A{get;set;} }   //A接口申明一个属性A

interface I_B  {int Count(int i,int j)} //B接口申明一个方法Count

interface I_C : I_A,I_B { }  //继承了A,B接口的C接口

public class I_D : IC

{ int a;

  public int A            //属性A外露到类I_D

   { get{return a;}

     set{a=value;}

    }

  public int Count(int i,int j)  //定义类I_D中的方法Count

    {return i+j+a;}

}
(3)外部对接口的访问(如果出现同名的参数或者方法,必须显式的指出他的父接口)

public interface I_A

{ int A{get;set}

  int Count(int i);

}

public interface I_B

double Count(double i);

}

public interface I_C : I_A,I_B { }

public class I_D

{ public void Sum(I_C ic)

  { ((I_A)ic).Count=1;  //显式表示I_A接口中的方法Count

    ((I_B)ic).Count(1); //显式表示I_B接口中的方法Count

     ic.Count(1);       //这种直接套用相关类型参数的表示方法也可以表示

     ic.Count(1.2);

   }

}

(4)外部类中对多重继承中的成员访问问题:

public interface I_A
{ string F(string A);
}
public interface I_B : I_A
{ new string F(string A);
}
public interface I_C : I_A
{ string T();
}

public interface I_D : I_B,I_C { }; //D接口多重继承接口A,B,C

public class I_F
public string Test(I_D id)  //接受参数类型为接口D类型
     id.T();    //直接调用C接口的T()方法
        id.F("B接口的方法");    //直接访问B接口被new的F方法取代A接口的那个F方法        ((I_A)id).F("A接口的方法");  //强行访问显式的A接口的F方法
((I_C)id).F("A接口的方法"); //强行访问C接口隐式的A接口F方法

((I_D)id).F("B接口的方法"); //直接访问D接口隐式的又被new的B接口F方法,而不是访问A接口中的

     }
}

(5)显式实现接口成员不能从类实例访问,但可以在类内部访问。当类使用者不需要使用该接口成员时以及多个接口之间有同名成员时,这个就特别有用。

public interface I_A
string Name { get;set;}
  string More();}

public class I_B : I_A
{ private string name;

  public I_B()   //初始化构造函数
    name = "天神";}

    #region I_A 成员(可以折叠)

    string I_A.Name   //显式实现的属性Name,没必要用到修饰符
     get { return name; }
        set { name = value; } }

    string I_A.More()   //显式实现的方法More
     string more = name + ",你好!";
        return more;
    }

    #endregion
}

(6)类继承类中的接口方法提供为虚的,表示接受任何扩充类的复写,复写可用override关键字

public interface I_A
{ string GetUrl();
  string GetName();
}

public class I_B : I_A
{ public virtual string GetUrl()
    { return "http://blog.sina.com.cn/tracymcgrady"; }
  public virtual string GetName()
    { return "天神的博客";}
}

public class I_C : I_B,I_A
{ string I_A.GetUrl()  //显式实现接口成员的执行体本身不能使用任何修饰符
    { return "http://sports.sina.com.cn";}
  string I_A.GetName()
    { return "新浪体育";}
}

public class I_D : I_B   //使用override关键字对I_B中的方法实现进行复写

{ public override string GetUrl()
    { return "http://you.video.sina.com.cn/m/1251200234";}
    public override string GetName()
    { return "天神的播客";}
}
public class I_E : I_B  //使用new关键字对I_B中的方法实现进行改写,直接把父类的方法取代了

{ public new string GetUrl()
    { return "火箭的排名是什么呢";}
    public new string GetName()
    { return "西部第二";}
}

(7)不同接口同名成员的访问:

public interface I_A
{ string G();}
public interface I_B
{ string G();}

public class I_C : I_A,I_B
 #region

    public string G()
    { return "隐式实现:欢迎光临天神的博客";}

    #endregion
    #region I_B 成员

    string I_B.G()
    { return "显式实现:欢迎光临天神的播客";}

    #endregion
}

(8)多个接口同名成员属性和方法的访问(一个属性一个方法):

public interface I_A
{ string A{get;set;}}  //A是属性
public interface I_B : I_A
{ string A();}        //A是方法

public class I_C : I_B
{ string I_B.A()
    { throw new Exception("The method or operation is not implemented.");}

  string I_A.A
    { get
        { throw new Exception("The method or operation is not implemented.");}
        set
        { throw new Exception("The method or operation is not implemented.");}
    }
}

(9) 显式实现的方法无法使用修饰符,同样可以使用虚方法Virtaul:在这个显式实现中调用另一个方法,然后这个被调用的方法再是虚方法

public interface I_A
   int Age { get;set;}
      string GetName();
      string GetPwd();  }

 public class I_B : I_9_A
     protected int age;
        protected string name;
        protected string pwd;

        public I_B(int a, string n, string p)
         age = a;
            name = n;
            pwd = p;}

        public int Age
        get { return age; }
           set { age = value; }}

        public virtual string GetName()
        return name;}
        public virtual string GetPwd()
        return pwd; }
    }
    public class I_C : I_B   

     public I_C(int a, string n, string p) : base(a, n, p)
        age = a;
           name = n;
           pwd = p;}
        public override string GetName()
        return "用户名:" + name;}
        public override string GetPwd()
        return "密码:" + pwd;}
    }

   public class I_D : I_A
     protected int age;
        protected string name;
        protected string pwd;

        public I_D(int a, string n, string p)
        age = a;
           name = n;
           pwd = p;}

        public int Age
        get { return age; }
           set { age = value; } }

        public string GetName()
        { return name;}
        public string GetPwd()
        { return pwd;}
    }
 public class I_E : I_D,I_A
    { public I_E(int a, string n, string p) : base(a, n, p)
        { age = a;
          name = n;
          pwd = p;}
      public string GetName()
      { return "用户名:" + name;}
      public string GetPwd()
      {return "密码:" + pwd;}
    }

(10)用抽象类来继承接口:

interface I_A
void F();
   void G();}

abstract class I_B1 : I_A
public void F()
   //执行代码 }
   public abstract void G();  //调用接口A的抽象方法G
}

class I_B2 : I_B1
public override void G()   //复写抽象类中的方法G
    { //执行代码 }
}


转自:http://blog.sina.com.cn/s/blog_4a93ccea0100cwqv.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值