深入继承——抽象类和接口
2016-10-25 17:43
417 查看
深入继承——抽象类和接口
一、基本概念
抽象类:又叫抽象基类:在定义的时候使用
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被这些修饰过的成员不能参与接口的实现。
下面针对抽象类和接口做一个详细的对比
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
一、基本概念
抽象类:又叫抽象基类:在定义的时候使用
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
相关文章推荐
- 深入继承 - 抽象类和接口
- 深入继承 - 抽象类和接口
- 深入继承之抽象类和接口综合分析及完整案列解说(一)
- 深入继承 - 抽象类和接口
- 深入继承之抽象类和接口综合分析及完整案列解说(二)
- 深入继承 - 抽象类和接口
- 深入继承 - 抽象类和接口
- 深入继承 - 抽象类和接口
- 黑马程序员——继承的深入学习:抽象类与接口(上)
- 深入继承 - 抽象类和接口
- 深入继承——抽象类和接口
- c#中的继承,抽象类,接口,运算符重载
- Java 抽象类 接口 继承 实现
- 深入理解Java的接口和抽象类
- 深入理解Java的接口和抽象类
- JAVA中几个易混淆关键词的理解:行为,隐藏,组合和继承,覆写和重载,多形(多态)性,动态绑定,上溯造型,抽象类,接口
- 深入理解Java的接口和抽象类
- java深入学习八之抽象类,接口
- 20.接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concreteclass)?
- java类、抽象类、接口、继承和对象解析